Waving Hands: a browser duel after Bartle's 1977 game
SvelteKit 5 single-player version against a heuristic bot. The engine resolves all forty spells simultaneously as the rules describe, the ledger of gestures is the interface, and the duel is saved in the browser. Tester feedback rounds added per-hand planning, threat evidence, a result strip with one-time rule explanations, a phone layout and a structured rules page. Deploys as a static site behind Caddy. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
commit
865555e911
38 files changed
+8112
No files matched your search
@@ -0,0 +1,91 @@
|
||||
<script lang="ts">
|
||||
import { FOE, YOU, type Duel } from '$lib/game/duel.svelte';
|
||||
import { glyph } from '$lib/game/glyphs';
|
||||
import { MAX_HP } from '$lib/game/state';
|
||||
|
||||
let { duel }: { duel: Duel } = $props();
|
||||
|
||||
const left = $derived(duel.forcedFor('main', 'left') ?? duel.sets.main.left.gesture);
|
||||
const right = $derived(duel.forcedFor('main', 'right') ?? duel.sets.main.right.gesture);
|
||||
</script>
|
||||
|
||||
{#if !duel.state.over}
|
||||
<div class="bar">
|
||||
<div class="health">
|
||||
<span><em>{duel.you.name}</em> {duel.you.hp}/{MAX_HP}</span>
|
||||
<span><em>{duel.foe.name}</em> {duel.foe.hp}/{MAX_HP}</span>
|
||||
</div>
|
||||
<div class="gestures" aria-label="Chosen gestures">
|
||||
<span class="letter" class:empty={left === null}>{duel.charmedHand === 'left' ? '?' : left === null ? '·' : glyph(left, right ?? '-')}</span>
|
||||
<span class="letter" class:empty={right === null}>{duel.charmedHand === 'right' ? '?' : right === null ? '·' : glyph(right, left ?? '-')}</span>
|
||||
</div>
|
||||
<button type="button" class="reveal" disabled={!duel.ready} onclick={() => duel.reveal()}>
|
||||
{duel.surrendering ? 'Surrender' : duel.timeStopped ? 'Act' : 'Reveal'}
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.bar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 860px) {
|
||||
.bar {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 5;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto auto;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
padding: 0.5rem 16px calc(0.5rem + env(safe-area-inset-bottom));
|
||||
background: var(--slate);
|
||||
border-top: 1px solid var(--rule-strong);
|
||||
}
|
||||
}
|
||||
|
||||
.health {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-size: 0.8rem;
|
||||
color: var(--bone-dim);
|
||||
font-variant-numeric: tabular-nums;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.health em {
|
||||
color: var(--bone);
|
||||
}
|
||||
|
||||
.gestures {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.letter {
|
||||
font-size: 1.6rem;
|
||||
color: var(--ember);
|
||||
min-width: 1.2em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.letter.empty {
|
||||
color: var(--bone-faint);
|
||||
}
|
||||
|
||||
.reveal {
|
||||
background: var(--bone);
|
||||
color: var(--slate-deep);
|
||||
border: 0;
|
||||
border-radius: 4px;
|
||||
padding: 0.5rem 1rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.reveal:disabled {
|
||||
opacity: 0.35;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user