your personal website on atproto - mirror
blento.app
1# Game Cards
2
3This folder contains interactive game cards (Tetris, Dino, etc.).
4
5## Implementation Requirements
6
7When creating a new game card, follow these patterns to ensure multiple games on the same page work independently.
8
9### 1. Container Setup
10
11Make the game container focusable and handle keyboard events on it (not on `svelte:window`):
12
13```svelte
14<script lang="ts">
15 let container: HTMLDivElement;
16</script>
17
18<!-- svelte-ignore a11y_no_noninteractive_tabindex a11y_no_noninteractive_element_interactions -->
19<div
20 bind:this={container}
21 class="relative h-full w-full overflow-hidden outline-none"
22 tabindex="0"
23 role="application"
24 aria-label="Your game name"
25 onkeydown={handleKeyDown}
26 onkeyup={handleKeyUp}
27>
28 <!-- game content -->
29</div>
30```
31
32### 2. Focus on Game Start
33
34When the game starts, focus the container so keyboard events work:
35
36```typescript
37function startGame() {
38 // ... game initialization
39 container?.focus();
40}
41```
42
43### 3. Keyboard Handlers
44
45Do NOT use `<svelte:window onkeydown={...} />` - this captures all keyboard events globally and causes all games to respond at once.
46
47Instead, attach handlers directly to the container div. The handlers will only fire when that specific game is focused.
48
49```typescript
50function handleKeyDown(e: KeyboardEvent) {
51 if (e.code === 'Space') {
52 e.preventDefault();
53 // handle action
54 }
55}
56```
57
58### 4. Canvas Setup
59
60Add `touch-none` and `select-none` classes to prevent scrolling and text selection during gameplay:
61
62```svelte
63<canvas
64 bind:this={canvas}
65 class="h-full w-full touch-none select-none"
66 ontouchstart={handleTouchStart}
67 ontouchmove={handleTouchMove}
68 ontouchend={handleTouchEnd}
69></canvas>
70```
71
72### 5. Touch Controls
73
74For mobile support, add touch event handlers to the canvas. Prevent default to stop page scrolling:
75
76```typescript
77function handleTouchStart(e: TouchEvent) {
78 if (gameState === 'playing') {
79 e.preventDefault();
80 }
81 // handle touch
82}
83```
84
85## Checklist for New Game Cards
86
87- [ ] Container has `bind:this={container}` reference
88- [ ] Container has `tabindex="0"` for focusability
89- [ ] Container has `role="application"` and `aria-label`
90- [ ] Container has `outline-none` class
91- [ ] Keyboard handlers are on container, NOT `svelte:window`
92- [ ] `startGame()` calls `container?.focus()`
93- [ ] Canvas has `touch-none select-none` classes
94- [ ] Touch handlers call `e.preventDefault()` when game is active
95- [ ] No `isTyping()` check needed (focus handles this automatically)