feat: add game starter component for physical robot game

This commit is contained in:
2025-08-26 02:12:57 +02:00
parent df3a48faed
commit bd1d677d6a
2 changed files with 116 additions and 0 deletions

View File

@@ -1,5 +1,6 @@
<script lang="ts">
// Landing page for the Schafkopf Bot.
import Game from './lib/Game.svelte';
</script>
<main id="app">
@@ -69,6 +70,25 @@
</ol>
</section>
<section id="game" class="game container">
<h3>Physical robot game</h3>
<p class="muted">Boot the robot into an in-person game and let it play as one of the four seats.</p>
<div class="grid">
<div>
<!-- Game starter component -->
<Game />
</div>
<div class="card">
<h4>Setup checklist</h4>
<ul>
<li>Connect robot to the local network.</li>
<li>Place the robot at the chosen seat and align card feeder.</li>
<li>Calibrate cameras and touch sensors if needed.</li>
</ul>
</div>
</div>
</section>
<section id="contact" class="contact container">
<h3>Get early access</h3>
<p>Interested in trying the bot or integrating it into a platform? Send a message and we'll reply with next steps.</p>

View File

@@ -0,0 +1,96 @@
<script lang="ts">
// Simple game starter UI that posts a start command to the backend.
import { writable } from 'svelte/store';
type Seat = 'North' | 'East' | 'South' | 'West';
let robotSeat: Seat = 'South';
let difficulty: 'easy' | 'medium' | 'hard' = 'medium';
let includeRobot = true;
let isStarting = false;
const logs = writable<string[]>([]);
function appendLog(line: string) {
logs.update((ls) => {
ls.push(line);
return ls.slice(-50);
});
}
async function startGame() {
isStarting = true;
appendLog(`Requesting new game (robotSeat=${robotSeat}, difficulty=${difficulty}, includeRobot=${includeRobot})`);
try {
const resp = await fetch('/api/game/start', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ robotSeat, difficulty, includeRobot }),
});
if (!resp.ok) {
const text = await resp.text();
throw new Error(text || resp.statusText);
}
const data = await resp.json();
appendLog('Game started: ' + JSON.stringify(data));
} catch (err) {
appendLog('Error starting game: ' + String(err));
} finally {
isStarting = false;
}
}
</script>
<section class="game-starter card">
<h4>Start a new physical game</h4>
<p class="muted">The robot will join as one of the four players and physically plays cards on the table.</p>
<div class="form-row">
<label>Robot seat</label>
<select bind:value={robotSeat} aria-label="Robot seat">
<option value="North">North</option>
<option value="East">East</option>
<option value="South">South</option>
<option value="West">West</option>
</select>
</div>
<div class="form-row">
<label>Difficulty</label>
<select bind:value={difficulty} aria-label="Difficulty">
<option value="easy">Easy</option>
<option value="medium">Medium</option>
<option value="hard">Hard</option>
</select>
</div>
<div class="form-row-inline">
<label><input type="checkbox" bind:checked={includeRobot} /> Include robot in this game</label>
</div>
<div class="actions">
<button class="btn primary" on:click={startGame} disabled={isStarting}> {isStarting ? 'Starting…' : 'Start game'} </button>
</div>
<div class="log">
<h5>Activity</h5>
<ul>
{#each $logs.slice().reverse() as line}
<li>{line}</li>
{/each}
</ul>
</div>
</section>
<style>
.game-starter { padding: 1rem; border-radius: 10px; }
.muted { color: var(--muted); margin-top: 0.25rem; }
.form-row { display:flex; flex-direction:column; gap:0.35rem; margin-top:0.8rem; }
.form-row-inline { margin-top:0.8rem; }
select { padding:0.5rem; border-radius:8px; background:transparent; color:inherit; border:1px solid rgba(255,255,255,0.04); }
.actions { margin-top:1rem; }
.log { margin-top:1rem; max-height:160px; overflow:auto; font-size:0.9rem; color:var(--muted); }
.log ul { list-style:none; padding:0; margin:0; display:flex; flex-direction:column; gap:0.25rem; }
</style>