mirror of
https://github.com/tiennm99/ai-coding-workflow-labs.git
synced 2026-09-19 00:21:30 +00:00
docs: complete project research for Pikachu Match tile-matching game
- STACK.md: Recommended Vite + TypeScript + Canvas minimal approach - FEATURES.md: Core matching mechanics and table stakes features - ARCHITECTURE.md: Layered architecture with state machine pattern - PITFALLS.md: Critical pitfalls (path-finding, board generation, dead-end detection) - SUMMARY.md: Synthesized findings with 6-phase roadmap suggestions
This commit is contained in:
@@ -0,0 +1,545 @@
|
||||
# Architecture Research
|
||||
|
||||
**Domain:** Tile-matching puzzle game (Pikachu Kawai / Onet Connect style)
|
||||
**Researched:** 2026-03-10
|
||||
**Confidence:** HIGH
|
||||
|
||||
## Standard Architecture
|
||||
|
||||
### System Overview
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ Presentation Layer │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ Renderer │ │ Audio │ │ UI │ │Animator │ │
|
||||
│ │ │ │ Manager │ │ Overlay │ │ │ │
|
||||
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
|
||||
│ │ │ │ │ │
|
||||
├───────┴─────────────┴─────────────┴─────────────┴───────────────┤
|
||||
│ Game Logic Layer │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ ┌──────────────────────────────────────────────────────────┐ │
|
||||
│ │ Game Loop (Core) │ │
|
||||
│ │ requestAnimationFrame → update() → render() │ │
|
||||
│ └──────────────────────────────────────────────────────────┘ │
|
||||
│ │ │ │ │ │
|
||||
│ ┌────┴────┐ ┌─────┴─────┐ ┌─────┴─────┐ ┌───┴────┐ │
|
||||
│ │ Input │ │ PathFinder│ │ Grid │ │ Score │ │
|
||||
│ │ Handler │ │ Engine │ │ Manager │ │System │ │
|
||||
│ └─────────┘ └───────────┘ └───────────┘ └────────┘ │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ State Layer │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ Idle │ │ Selected │ │ Matching │ │ GameOver │ │
|
||||
│ │ State │ │ State │ │ State │ │ State │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
|
||||
├─────────────────────────────────────────────────────────────────┤
|
||||
│ Data Layer │
|
||||
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ Tile │ │ Game │ │ Config │ │
|
||||
│ │ Model │ │ State │ │Constants │ │
|
||||
│ └──────────┘ └──────────┘ └──────────┘ │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Component Responsibilities
|
||||
|
||||
| Component | Responsibility | Typical Implementation |
|
||||
|-----------|----------------|------------------------|
|
||||
| **Game Loop** | Orchestrates update/render cycle, timing | requestAnimationFrame with delta time |
|
||||
| **Grid Manager** | Owns tile grid, handles tile state, generates layouts | 2D array of tile objects |
|
||||
| **Input Handler** | Captures clicks/touches, translates to grid coordinates | Event listeners on canvas/container |
|
||||
| **PathFinder** | Validates connections using ≤3 line algorithm | BFS/DFS with turn counting |
|
||||
| **Renderer** | Draws grid, tiles, connection lines, animations | Canvas 2D API or DOM elements |
|
||||
| **State Machine** | Manages game states (idle, selected, matching, over) | Finite state machine pattern |
|
||||
| **Score System** | Tracks points, combos, game progress | Simple counter with multipliers |
|
||||
| **Animator** | Handles tile disappear, connection line, UI effects | Tween/interpolation functions |
|
||||
| **UI Overlay** | Score display, hints, restart button | DOM elements layered over game |
|
||||
|
||||
## Recommended Project Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── core/ # Core game engine
|
||||
│ ├── GameLoop.ts # Main loop, timing, frame management
|
||||
│ ├── EventEmitter.ts # Pub/sub for component communication
|
||||
│ └── StateMachine.ts # Finite state machine base
|
||||
│
|
||||
├── game/ # Game-specific logic
|
||||
│ ├── Grid.ts # Tile grid, layout generation
|
||||
│ ├── Tile.ts # Tile model, types, state
|
||||
│ ├── PathFinder.ts # Connection validation algorithm
|
||||
│ ├── MatchEngine.ts # Match detection and execution
|
||||
│ └── MoveDetector.ts # Detects when no moves remain
|
||||
│
|
||||
├── input/ # Input handling
|
||||
│ ├── InputHandler.ts # Mouse/touch event processing
|
||||
│ └── GridCoordinate.ts # Screen-to-grid coordinate conversion
|
||||
│
|
||||
├── renderer/ # Visual output
|
||||
│ ├── Renderer.ts # Main canvas renderer
|
||||
│ ├── TileRenderer.ts # Tile drawing logic
|
||||
│ ├── ConnectionRenderer.ts # Path line drawing
|
||||
│ └── AnimationManager.ts # Animation queue and execution
|
||||
│
|
||||
├── state/ # Game states
|
||||
│ ├── GameState.ts # State interface
|
||||
│ ├── IdleState.ts # Waiting for first selection
|
||||
│ ├── SelectedState.ts # First tile selected, awaiting second
|
||||
│ ├── MatchingState.ts # Processing match attempt
|
||||
│ ├── AnimatingState.ts # Playing match/shuffle animation
|
||||
│ └── GameOverState.ts # No moves or all cleared
|
||||
│
|
||||
├── systems/ # Supporting systems
|
||||
│ ├── ScoreSystem.ts # Points, combos, high score
|
||||
│ ├── HintSystem.ts # Optional hint generation
|
||||
│ └── SoundSystem.ts # Audio feedback (future)
|
||||
│
|
||||
├── config/ # Configuration
|
||||
│ ├── GameConfig.ts # Grid size, tile types, timing
|
||||
│ └── Constants.ts # Magic numbers, colors, sizes
|
||||
│
|
||||
├── utils/ # Utilities
|
||||
│ ├── Shuffle.ts # Fisher-Yates for tile distribution
|
||||
│ └── MathUtils.ts # Interpolation, easing functions
|
||||
│
|
||||
├── assets/ # Static resources
|
||||
│ ├── sprites/ # Pokemon tile images
|
||||
│ └── sounds/ # Audio files (future)
|
||||
│
|
||||
└── main.ts # Entry point, initialization
|
||||
```
|
||||
|
||||
### Structure Rationale
|
||||
|
||||
- **core/:** Reusable engine pieces, game-agnostic
|
||||
- **game/:** All tile-matching specific logic, isolated for easy modification
|
||||
- **renderer/:** Drawing logic separated from game logic for testability
|
||||
- **state/:** Each state is its own file following State pattern
|
||||
- **systems/:** Cross-cutting concerns that don't fit single components
|
||||
|
||||
## Architectural Patterns
|
||||
|
||||
### Pattern 1: Game Loop
|
||||
|
||||
**What:** Central orchestration that runs every frame, calling update (logic) then render (visual).
|
||||
|
||||
**When to use:** Always for real-time games. The heartbeat of any browser game.
|
||||
|
||||
**Trade-offs:**
|
||||
- Pro: Consistent frame-based updates, smooth animation
|
||||
- Con: Must handle variable frame rates (delta time)
|
||||
|
||||
**Example:**
|
||||
```typescript
|
||||
class GameLoop {
|
||||
private lastTime = 0;
|
||||
private running = false;
|
||||
|
||||
start() {
|
||||
this.running = true;
|
||||
this.lastTime = performance.now();
|
||||
requestAnimationFrame((time) => this.loop(time));
|
||||
}
|
||||
|
||||
private loop(currentTime: number) {
|
||||
if (!this.running) return;
|
||||
|
||||
const deltaTime = (currentTime - this.lastTime) / 1000;
|
||||
this.lastTime = currentTime;
|
||||
|
||||
this.update(deltaTime); // Logic first
|
||||
this.render(); // Then draw
|
||||
|
||||
requestAnimationFrame((t) => this.loop(t));
|
||||
}
|
||||
|
||||
private update(dt: number) {
|
||||
this.stateMachine.update(dt);
|
||||
this.animationManager.update(dt);
|
||||
}
|
||||
|
||||
private render() {
|
||||
this.renderer.clear();
|
||||
this.renderer.drawGrid(this.grid);
|
||||
this.animationManager.render(this.renderer);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 2: Component
|
||||
|
||||
**What:** Break game entities into composable behaviors instead of deep inheritance.
|
||||
|
||||
**When to use:** When entities have orthogonal behaviors (visual, clickable, animated).
|
||||
|
||||
**Trade-offs:**
|
||||
- Pro: Flexible, composable, easy to add/remove features
|
||||
- Con: More indirection, can be overkill for simple games
|
||||
|
||||
**Example:**
|
||||
```typescript
|
||||
// Tile as composition of behaviors
|
||||
interface TileComponent {
|
||||
update(dt: number): void;
|
||||
}
|
||||
|
||||
class Tile {
|
||||
private components: TileComponent[] = [];
|
||||
|
||||
addComponent(component: TileComponent) {
|
||||
this.components.push(component);
|
||||
}
|
||||
|
||||
update(dt: number) {
|
||||
for (const comp of this.components) {
|
||||
comp.update(dt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Specific behaviors
|
||||
class VisualComponent implements TileComponent {
|
||||
constructor(private sprite: Sprite) {}
|
||||
|
||||
update(dt: number) {
|
||||
// Update visual state
|
||||
}
|
||||
|
||||
render(ctx: CanvasRenderingContext2D) {
|
||||
this.sprite.draw(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
class SelectableComponent implements TileComponent {
|
||||
isSelected = false;
|
||||
|
||||
update(dt: number) {
|
||||
// Handle selection highlight
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 3: State Machine
|
||||
|
||||
**What:** Define discrete game states with explicit transitions. Each state handles its own input and logic.
|
||||
|
||||
**When to use:** When game has distinct modes (idle, selected, animating, game over).
|
||||
|
||||
**Trade-offs:**
|
||||
- Pro: Clear state boundaries, easy to reason about, prevents invalid states
|
||||
- Con: More boilerplate than simple boolean flags
|
||||
|
||||
**Example:**
|
||||
```typescript
|
||||
interface GameState {
|
||||
enter(): void;
|
||||
exit(): void;
|
||||
handleInput(x: number, y: number): void;
|
||||
update(dt: number): void;
|
||||
}
|
||||
|
||||
class StateMachine {
|
||||
private current: GameState;
|
||||
|
||||
transition(to: GameState) {
|
||||
if (this.current) this.current.exit();
|
||||
this.current = to;
|
||||
this.current.enter();
|
||||
}
|
||||
|
||||
handleInput(x: number, y: number) {
|
||||
this.current.handleInput(x, y);
|
||||
}
|
||||
|
||||
update(dt: number) {
|
||||
this.current.update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
// Concrete states
|
||||
class IdleState implements GameState {
|
||||
constructor(private game: Game) {}
|
||||
|
||||
handleInput(x: number, y: number) {
|
||||
const tile = this.game.grid.getTileAt(x, y);
|
||||
if (tile && !tile.cleared) {
|
||||
this.game.selectTile(tile);
|
||||
this.game.stateMachine.transition(new SelectedState(this.game, tile));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SelectedState implements GameState {
|
||||
constructor(private game: Game, private firstTile: Tile) {}
|
||||
|
||||
handleInput(x: number, y: number) {
|
||||
const tile = this.game.grid.getTileAt(x, y);
|
||||
if (tile === this.firstTile) {
|
||||
// Deselect
|
||||
this.game.deselectTile(tile);
|
||||
this.game.stateMachine.transition(new IdleState(this.game));
|
||||
} else if (tile && !tile.cleared && tile.type === this.firstTile.type) {
|
||||
// Attempt match
|
||||
this.game.stateMachine.transition(new MatchingState(this.game, this.firstTile, tile));
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Pattern 4: Observer/Event Emitter
|
||||
|
||||
**What:** Components communicate through events rather than direct references.
|
||||
|
||||
**When to use:** When multiple systems need to react to the same event (tile matched, game over).
|
||||
|
||||
**Trade-offs:**
|
||||
- Pro: Loose coupling, easy to add new listeners
|
||||
- Con: Harder to trace event flow, potential for memory leaks
|
||||
|
||||
**Example:**
|
||||
```typescript
|
||||
class EventEmitter {
|
||||
private listeners: Map<string, Function[]> = new Map();
|
||||
|
||||
on(event: string, callback: Function) {
|
||||
if (!this.listeners.has(event)) {
|
||||
this.listeners.set(event, []);
|
||||
}
|
||||
this.listeners.get(event)!.push(callback);
|
||||
}
|
||||
|
||||
emit(event: string, data?: any) {
|
||||
const callbacks = this.listeners.get(event);
|
||||
if (callbacks) {
|
||||
callbacks.forEach(cb => cb(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Usage
|
||||
game.events.on('tileMatched', (tiles: Tile[]) => {
|
||||
scoreSystem.addPoints(tiles);
|
||||
soundSystem.play('match');
|
||||
});
|
||||
|
||||
game.events.on('noMovesRemaining', () => {
|
||||
stateMachine.transition(new GameOverState());
|
||||
});
|
||||
```
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Input Flow
|
||||
|
||||
```
|
||||
[Click/Touch Event]
|
||||
↓
|
||||
[InputHandler] → Converts screen coords to grid coords
|
||||
↓
|
||||
[StateMachine.handleInput(x, y)]
|
||||
↓
|
||||
[Current State] → Determines action based on game state
|
||||
↓
|
||||
[Grid.getTileAt(x, y)] → Retrieves tile at position
|
||||
↓
|
||||
[PathFinder.findPath(tileA, tileB)] → Validates connection
|
||||
↓
|
||||
[MatchEngine.executeMatch()] → Clears tiles, emits event
|
||||
↓
|
||||
[ScoreSystem] ← Events: 'tileMatched'
|
||||
↓
|
||||
[Renderer] ← Updated grid state
|
||||
```
|
||||
|
||||
### State Flow
|
||||
|
||||
```
|
||||
┌─────────┐ click tile ┌──────────┐ click matching ┌───────────┐
|
||||
│ Idle │ ──────────────→ │ Selected │ ─────────────────→ │ Matching │
|
||||
│ State │ │ State │ │ State │
|
||||
└─────────┘ └──────────┘ └───────────┘
|
||||
↑ │ │
|
||||
│ │ click same tile │
|
||||
│ │ (deselect) │ match
|
||||
└──────────────────────────────┘ │ valid
|
||||
↓
|
||||
┌───────────┐
|
||||
│Animating │
|
||||
│ State │
|
||||
└───────────┘
|
||||
│
|
||||
┌──────────────────────────┼──────────────────────────┐
|
||||
│ animation complete │ animation complete │
|
||||
↓ ↓ ↓
|
||||
┌─────────┐ ┌───────────┐ ┌──────────┐
|
||||
│ Idle │ │ GameOver │ │ Win │
|
||||
│ State │ │ State │ │ State │
|
||||
└─────────┘ └───────────┘ └──────────┘
|
||||
↑ │ │
|
||||
│ │ restart │ restart
|
||||
└──────────────────────────┴──────────────────────────┘
|
||||
```
|
||||
|
||||
### Key Data Flows
|
||||
|
||||
1. **Tile Selection Flow:** Input → Grid coordinate → Tile lookup → State transition → Visual feedback (highlight)
|
||||
|
||||
2. **Match Validation Flow:** Two tiles selected → PathFinder finds valid path → MatchEngine clears tiles → Events emitted → Score updated, animation triggered
|
||||
|
||||
3. **Game Over Detection Flow:** Every match → MoveDetector checks remaining pairs → No valid moves → Event emitted → State transition to GameOver
|
||||
|
||||
4. **Render Flow:** Game loop tick → State update → Grid state read → Renderer draws tiles → Animation layer draws effects → UI layer draws score
|
||||
|
||||
## Scaling Considerations
|
||||
|
||||
| Scale | Architecture Adjustments |
|
||||
|-------|--------------------------|
|
||||
| Single session (v1) | All state in memory, Canvas 2D, simple requestAnimationFrame loop |
|
||||
| Local persistence | Add localStorage for high scores, game state serialization |
|
||||
| Mobile performance | Use requestIdleCallback for non-critical updates, sprite atlas for tiles |
|
||||
| Complex animations | Introduce animation queue, easing library, consider WebGL for effects |
|
||||
|
||||
### Scaling Priorities
|
||||
|
||||
1. **First bottleneck:** Canvas redraw performance on large grids. Fix with dirty rectangle rendering (only redraw changed tiles).
|
||||
|
||||
2. **Second bottleneck:** Memory with many tile assets. Fix with sprite atlas and lazy loading.
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
### Anti-Pattern 1: God Object Game Class
|
||||
|
||||
**What people do:** Put all game logic in one massive `Game` class.
|
||||
|
||||
**Why it's wrong:** Unmaintainable, hard to test, impossible to reason about state.
|
||||
|
||||
**Do this instead:** Separate concerns into Grid, PathFinder, Renderer, StateMachine. Game class just wires them together.
|
||||
|
||||
### Anti-Pattern 2: Direct DOM Manipulation for Game State
|
||||
|
||||
**What people do:** Store tile state in DOM elements (data attributes, classes).
|
||||
|
||||
**Why it's wrong:** DOM is for presentation, not state. Slow to query, easy to get out of sync.
|
||||
|
||||
**Do this instead:** Keep game state in plain objects/arrays. Render to DOM/Canvas as output only.
|
||||
|
||||
### Anti-Pattern 3: Blocking Animations
|
||||
|
||||
**What people do:** Use setTimeout/setInterval for animations and wait for completion before accepting input.
|
||||
|
||||
**Why it's wrong:** Janky, blocks user, timing issues on different frame rates.
|
||||
|
||||
**Do this instead:** Use requestAnimationFrame with delta time, animation state machine that allows input during animations.
|
||||
|
||||
### Anti-Pattern 4: Tight Coupling Between Logic and Rendering
|
||||
|
||||
**What people do:** PathFinder draws the connection line directly.
|
||||
|
||||
**Why it's wrong:** Can't test logic without rendering, can't change rendering without touching logic.
|
||||
|
||||
**Do this instead:** PathFinder returns path data. Renderer takes path data and draws it. Complete separation.
|
||||
|
||||
## Build Order Implications
|
||||
|
||||
Based on dependencies between components, recommended build order:
|
||||
|
||||
### Phase 1: Core Foundation
|
||||
1. **GameConfig/Constants** - No dependencies, everything needs this
|
||||
2. **EventEmitter** - No dependencies, enables loose coupling
|
||||
3. **GameLoop** - Minimal, just frame management
|
||||
4. **Tile model** - Simple data structure
|
||||
|
||||
**Why first:** These have no dependencies and everything else builds on them.
|
||||
|
||||
### Phase 2: Grid and State
|
||||
5. **Grid Manager** - Depends on Tile, Config
|
||||
6. **StateMachine base** - No game dependencies
|
||||
7. **IdleState** - Simplest state, entry point
|
||||
8. **InputHandler** - Needs Grid for coordinate conversion
|
||||
|
||||
**Why second:** Establishes the game board and basic interaction.
|
||||
|
||||
### Phase 3: Core Mechanics
|
||||
9. **PathFinder** - Depends on Grid, standalone algorithm
|
||||
10. **SelectedState** - Depends on IdleState transition
|
||||
11. **MatchingState** - Depends on PathFinder
|
||||
12. **Renderer (basic)** - Needs Grid, Tile
|
||||
|
||||
**Why third:** Implements the core matching mechanic. Playable at this point.
|
||||
|
||||
### Phase 4: Polish
|
||||
13. **AnimatingState** - Depends on MatchingState
|
||||
14. **AnimationManager** - Depends on Renderer
|
||||
15. **ScoreSystem** - Listens to events
|
||||
16. **MoveDetector** - Depends on Grid, PathFinder
|
||||
17. **GameOverState** - Depends on MoveDetector
|
||||
|
||||
**Why last:** Enhances the core loop but not required for basic functionality.
|
||||
|
||||
### Dependency Graph
|
||||
|
||||
```
|
||||
Config ─────────────────────────────────────────┐
|
||||
│ │
|
||||
▼ │
|
||||
Tile ◄─────────────────────────────────────┐ │
|
||||
│ │ │
|
||||
▼ │ │
|
||||
Grid ◄──────────────────────────────────┐ │ │
|
||||
│ │ │ │
|
||||
├─────────────────────────────────────┼──┼────┤
|
||||
▼ │ │ │
|
||||
PathFinder │ │ │
|
||||
│ │ │ │
|
||||
▼ │ │ │
|
||||
MatchEngine ────────────────────────► │ │ │
|
||||
│ │ │
|
||||
EventEmitter ◄──────────────────────────┼──┼────┘
|
||||
│ │ │
|
||||
▼ │ │
|
||||
StateMachine ◄──────────────────────────┼──┤
|
||||
│ │ │
|
||||
├─────────────────────────────────────┤ │
|
||||
▼ │ │
|
||||
[States: Idle → Selected → Matching] │ │
|
||||
│ │
|
||||
InputHandler ───────────────────────────┘ │
|
||||
│ │
|
||||
▼ │
|
||||
Renderer ◄─────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Integration Points
|
||||
|
||||
### External Services
|
||||
|
||||
| Service | Integration Pattern | Notes |
|
||||
|---------|---------------------|-------|
|
||||
| localStorage | Direct API for persistence | Save/load high scores, game state |
|
||||
| Pokemon sprite assets | Static file loading | Load at startup, cache in memory |
|
||||
|
||||
### Internal Boundaries
|
||||
|
||||
| Boundary | Communication | Notes |
|
||||
|----------|---------------|-------|
|
||||
| Game Loop ↔ State Machine | Direct method calls | Synchronous, every frame |
|
||||
| State Machine ↔ Grid | Direct reads | State queries grid, doesn't modify directly |
|
||||
| MatchEngine → Events | EventEmitter | Decoupled, multiple listeners possible |
|
||||
| InputHandler → State Machine | Method call | Passes grid coordinates |
|
||||
| Renderer ← Grid | Pull model | Renderer reads grid state each frame |
|
||||
|
||||
## Sources
|
||||
|
||||
- MDN Game Development - Anatomy of a video game: https://developer.mozilla.org/en-US/docs/Games/Anatomy
|
||||
- MDN Game Development - The game loop: https://developer.mozilla.org/en-US/docs/Games/Anatomy_of_a_game_loop
|
||||
- Game Programming Patterns by Robert Nystrom - Game Loop pattern: https://gameprogrammingpatterns.com/game-loop.html
|
||||
- Game Programming Patterns - Component pattern: https://gameprogrammingpatterns.com/component.html
|
||||
- Game Programming Patterns - State pattern: https://gameprogrammingpatterns.com/state.html
|
||||
|
||||
---
|
||||
*Architecture research for: tile-matching puzzle game (Pikachu Match)*
|
||||
*Researched: 2026-03-10*
|
||||
@@ -0,0 +1,181 @@
|
||||
# Feature Research
|
||||
|
||||
**Domain:** Tile-matching puzzle games (Onet Connect / Pikachu Kawai style)
|
||||
**Researched:** 2026-03-10
|
||||
**Confidence:** MEDIUM
|
||||
|
||||
## Feature Landscape
|
||||
|
||||
### Table Stakes (Users Expect These)
|
||||
|
||||
Features users assume exist. Missing these = product feels incomplete.
|
||||
|
||||
| Feature | Why Expected | Complexity | Notes |
|
||||
|---------|--------------|------------|-------|
|
||||
| Grid of paired tiles | Core mechanic - every game in this genre has this | LOW | Always even number of tiles, each type appears in pairs |
|
||||
| Click-to-select matching | Standard interaction pattern | LOW | Click first tile to select, click second matching tile to attempt connection |
|
||||
| Path validation (max 3 lines) | Core rule - tiles connect if path uses 3 or fewer straight lines | MEDIUM | Algorithm checks: direct line, 1 turn (L-shape), 2 turns (U/Z-shape) |
|
||||
| Matched tiles disappear | Visual feedback that match succeeded | LOW | Clear animation, tiles removed from grid |
|
||||
| Timer / time pressure | Creates urgency - players expect this challenge | LOW | Countdown or elapsed time display |
|
||||
| Score display | Players want to track performance | LOW | Points for matches, bonus for speed |
|
||||
| Hint system | Prevents frustration when stuck | MEDIUM | Highlights one valid pair |
|
||||
| Shuffle feature | Recovery when no moves available | MEDIUM | Rearranges remaining tiles randomly |
|
||||
| Win condition detection | Game knows when all pairs matched | LOW | Check if board is empty |
|
||||
| Lose condition (time out) | Failure state for time pressure | LOW | Timer reaches zero |
|
||||
| No moves detection | Game detects when no valid pairs exist | MEDIUM | Check all remaining pairs for valid paths |
|
||||
| Responsive layout | Works on desktop and mobile browsers | MEDIUM | Touch and mouse input support |
|
||||
|
||||
### Differentiators (Competitive Advantage)
|
||||
|
||||
Features that set the product apart. Not required, but valuable.
|
||||
|
||||
| Feature | Value Proposition | Complexity | Notes |
|
||||
|---------|-------------------|------------|-------|
|
||||
| Visual connection preview | Shows the path line before confirming match | MEDIUM | Helps new players learn the rules |
|
||||
| Multiple tile themes | Variety keeps game fresh (animals, fruits, icons) | LOW | Swap tile images, same mechanics |
|
||||
| Level progression | Increasing difficulty maintains engagement | MEDIUM | Larger grids, more tile types, less time |
|
||||
| Combo/scoring multipliers | Rewards skilled/fast play | MEDIUM | Chain matches, speed bonuses |
|
||||
| Animated match effects | Satisfying visual feedback | MEDIUM | Particles, scaling, glow effects |
|
||||
| Sound effects | Audio feedback enhances satisfaction | LOW | Match sounds, error sounds, win/lose jingles |
|
||||
| Local high score | Persistence without backend | LOW | Store in localStorage |
|
||||
| Undo last move | Forgiveness for misclicks | MEDIUM | Remember previous state |
|
||||
| Tutorial overlay | First-time player guidance | LOW | Visual guide showing valid connection patterns |
|
||||
| Dark/light theme | Accessibility and preference | LOW | CSS variable swap |
|
||||
| Keyboard controls | Alternative to mouse for accessibility | MEDIUM | Arrow keys + enter to select tiles |
|
||||
| Auto-save progress | Resume later if interrupted | MEDIUM | Save game state to localStorage |
|
||||
|
||||
### Anti-Features (Commonly Requested, Often Problematic)
|
||||
|
||||
Features that seem good but create problems.
|
||||
|
||||
| Feature | Why Requested | Why Problematic | Alternative |
|
||||
|---------|---------------|-----------------|-------------|
|
||||
| Unlimited hints without penalty | Players want help when stuck | Removes all challenge, trivializes game | Limited hints per level, hints cost points |
|
||||
| No timer option | Some players dislike pressure | Removes core tension that makes game engaging | Relaxed mode as unlockable, not default |
|
||||
| Auto-match button | "Just do it for me" | Turns game into watching, not playing | Better hint system that teaches patterns |
|
||||
| Complex power-ups (bombs, freezes) | Adds "excitement" | Bloats simple elegant mechanic, confuses new players | Keep power-ups minimal (hint, shuffle only) |
|
||||
| Multiplayer competitive | "Play with friends" | Significantly increases scope, needs backend | Local high score comparison instead |
|
||||
| In-app purchases | Revenue generation | Adds friction, feels predatory in simple game | Ad-supported or one-time purchase |
|
||||
| Facebook/social login | "Share scores easily" | Privacy concerns, third-party dependency | Local storage, optional screenshot sharing |
|
||||
| Daily challenges | "Reason to return daily" | Needs content pipeline, backend for consistency | Procedural levels with seed-based generation |
|
||||
|
||||
## Feature Dependencies
|
||||
|
||||
```
|
||||
Grid Rendering
|
||||
└──requires──> Tile Selection
|
||||
└──requires──> Path Validation
|
||||
└──requires──> Match Animation
|
||||
└──requires──> Score Update
|
||||
|
||||
No Moves Detection
|
||||
└──enables──> Shuffle Feature
|
||||
|
||||
Timer System
|
||||
└──conflicts──> Untimed/Relaxed Mode (different game modes)
|
||||
|
||||
Hint System
|
||||
└──requires──> Path Validation (reuse algorithm)
|
||||
|
||||
Level Progression
|
||||
└──requires──> Win Condition Detection
|
||||
└──requires──> Level Data (grid size, tile types, time limit)
|
||||
|
||||
Local High Score
|
||||
└──requires──> Score Display
|
||||
```
|
||||
|
||||
### Dependency Notes
|
||||
|
||||
- **Hint System requires Path Validation:** Hints must find valid pairs using the same pathfinding algorithm
|
||||
- **No Moves Detection enables Shuffle:** Shuffle only makes sense when player is stuck
|
||||
- **Timer System conflicts with Relaxed Mode:** Different game modes, should be separate options
|
||||
- **Level Progression requires multiple systems:** Win detection to advance, level data to configure next board
|
||||
|
||||
## MVP Definition
|
||||
|
||||
### Launch With (v1)
|
||||
|
||||
Minimum viable product - what's needed to validate the concept.
|
||||
|
||||
- [x] Grid of paired tiles (even count, matched pairs) - Core mechanic
|
||||
- [x] Click-to-select two matching tiles - Standard interaction
|
||||
- [x] Path validation (max 3 straight lines / 2 turns) - Core rule
|
||||
- [x] Matched tiles disappear with animation - Visual feedback
|
||||
- [x] Score display - Performance tracking
|
||||
- [x] Timer with lose condition - Time pressure
|
||||
- [x] Win condition (board cleared) - Success state
|
||||
- [x] No moves detection + shuffle - Recovery mechanism
|
||||
- [x] Responsive grid (desktop + mobile) - Platform requirement
|
||||
|
||||
### Add After Validation (v1.x)
|
||||
|
||||
Features to add once core is working.
|
||||
|
||||
- [ ] Hint system (limited uses) - Prevents frustration
|
||||
- [ ] Visual connection preview - Helps learn rules
|
||||
- [ ] Local high score (localStorage) - Persistence without backend
|
||||
- [ ] Sound effects - Audio satisfaction
|
||||
- [ ] Tutorial overlay for first-time players - Onboarding
|
||||
|
||||
### Future Consideration (v2+)
|
||||
|
||||
Features to defer until product-market fit is established.
|
||||
|
||||
- [ ] Multiple tile themes - Visual variety
|
||||
- [ ] Level progression with difficulty scaling - Long-term engagement
|
||||
- [ ] Combo multipliers - Depth for skilled players
|
||||
- [ ] Dark/light theme toggle - Accessibility
|
||||
- [ ] Keyboard controls - Accessibility
|
||||
- [ ] Undo last move - Forgiveness
|
||||
|
||||
## Feature Prioritization Matrix
|
||||
|
||||
| Feature | User Value | Implementation Cost | Priority |
|
||||
|---------|------------|---------------------|----------|
|
||||
| Grid + tile rendering | HIGH | LOW | P1 |
|
||||
| Click selection | HIGH | LOW | P1 |
|
||||
| Path validation (3 lines) | HIGH | MEDIUM | P1 |
|
||||
| Match animation + removal | HIGH | LOW | P1 |
|
||||
| Score display | MEDIUM | LOW | P1 |
|
||||
| Timer + lose condition | HIGH | LOW | P1 |
|
||||
| Win condition | HIGH | LOW | P1 |
|
||||
| No moves detection | HIGH | MEDIUM | P1 |
|
||||
| Shuffle feature | HIGH | MEDIUM | P1 |
|
||||
| Responsive layout | HIGH | MEDIUM | P1 |
|
||||
| Hint system | MEDIUM | MEDIUM | P2 |
|
||||
| Connection preview | MEDIUM | MEDIUM | P2 |
|
||||
| Local high score | MEDIUM | LOW | P2 |
|
||||
| Sound effects | MEDIUM | LOW | P2 |
|
||||
| Tutorial overlay | MEDIUM | LOW | P2 |
|
||||
| Multiple themes | LOW | LOW | P3 |
|
||||
| Level progression | MEDIUM | HIGH | P3 |
|
||||
| Combo scoring | LOW | MEDIUM | P3 |
|
||||
|
||||
**Priority key:**
|
||||
- P1: Must have for launch
|
||||
- P2: Should have, add when possible
|
||||
- P3: Nice to have, future consideration
|
||||
|
||||
## Competitor Feature Analysis
|
||||
|
||||
| Feature | Onet Connect Classic (CrazyGames) | Pikachu Kawai | Our Approach |
|
||||
|---------|-----------------------------------|---------------|--------------|
|
||||
| Core mechanic | Match pairs via 3-line paths | Same | Same - proven formula |
|
||||
| Timer | Yes, countdown | Yes | Yes - core tension |
|
||||
| Hints | 3 free, then watch ad | Limited hints | Limited hints (no ads) |
|
||||
| Shuffle | Earned through wins | Yes | Always available when stuck |
|
||||
| Themes | Animals, candy, fruits | Pokemon only | Pokemon theme (per project) |
|
||||
| Levels | Progressive difficulty | Multiple levels | Single level for v1 |
|
||||
| Ads | Yes (between games) | Varies by version | None for v1 |
|
||||
| Mobile support | Yes | Yes | Yes - responsive |
|
||||
|
||||
## Sources
|
||||
|
||||
- [Onet Connect Classic - CrazyGames](https://www.crazygames.com/game/onet-connect-classic) - Feature analysis: timer, hints, shuffle, themes, levels
|
||||
- Project context from PROJECT.md - Core requirements and constraints
|
||||
- Domain knowledge of tile-matching puzzle genre conventions
|
||||
|
||||
---
|
||||
*Feature research for: Tile-matching puzzle games (Onet Connect style)*
|
||||
*Researched: 2026-03-10*
|
||||
@@ -0,0 +1,263 @@
|
||||
# Domain Pitfalls
|
||||
|
||||
**Domain:** Tile-Matching Puzzle Game (Pikachu Match)
|
||||
**Researched:** 2026-03-10
|
||||
**Confidence:** MEDIUM (based on domain knowledge; web research was limited)
|
||||
|
||||
## Critical Pitfalls
|
||||
|
||||
Mistakes that cause rewrites or major issues.
|
||||
|
||||
### Pitfall 1: Incorrect Path-Finding Algorithm Implementation
|
||||
|
||||
**What goes wrong:** The 3-line (2-turn) path-finding logic incorrectly validates or rejects connections. Either valid matches are rejected (frustrating players) or invalid matches are accepted (breaking game logic).
|
||||
|
||||
**Why it happens:** Developers underestimate the complexity of checking all possible paths. The algorithm must check horizontal-first paths AND vertical-first paths, and handle edge cases like paths hugging the board boundary or passing through cleared tiles.
|
||||
|
||||
**Consequences:** Players lose trust in the game when obvious matches fail or invalid matches succeed. Core loop feels broken.
|
||||
|
||||
**Prevention:**
|
||||
1. Implement the path check as: straight line (0 turns), one-turn path (L-shape), two-turn path (U-shape or Z-shape)
|
||||
2. Test exhaustively with unit tests covering: adjacent tiles, straight-line connections, single-turn connections, double-turn connections, boundary-hugging paths, paths through cleared areas
|
||||
3. Visualize valid paths during development to debug visually
|
||||
|
||||
**Detection:** Unit tests fail; players report "I clicked matching tiles and nothing happened" or "tiles that shouldn't match did"
|
||||
|
||||
**Phase to address:** Phase 1 (Core Matching Logic)
|
||||
|
||||
---
|
||||
|
||||
### Pitfall 2: Unsolvable Board Generation
|
||||
|
||||
**What goes wrong:** The game generates a board where no valid moves exist from the start, or becomes unsolvable partway through, but the dead-end detection doesn't trigger.
|
||||
|
||||
**Why it happens:** Random tile placement doesn't guarantee solvability. Developers assume "if pairs exist, matches must exist" — but pairs can be blocked by the 3-line constraint.
|
||||
|
||||
**Consequences:** Players get stuck through no fault of their own. Game feels unfair. Frustration leads to abandonment.
|
||||
|
||||
**Prevention:**
|
||||
1. Generate boards by placing pairs in reverse: start with empty board, add matched pairs in positions that are guaranteed connectable
|
||||
2. Alternatively, after random generation, validate solvability and regenerate if unsolvable
|
||||
3. Implement a "shuffle" feature that preserves remaining tiles but repositions them when no moves exist
|
||||
|
||||
**Detection:** Manual testing reveals boards with no valid moves; automated solvability checker fails
|
||||
|
||||
**Phase to address:** Phase 2 (Board Generation)
|
||||
|
||||
---
|
||||
|
||||
### Pitfall 3: Dead-End Detection Failure
|
||||
|
||||
**What goes wrong:** The game fails to detect when no valid moves remain, leaving players stuck with no feedback or resolution.
|
||||
|
||||
**Why it happens:** Dead-end detection requires checking ALL remaining tile pairs against ALL possible paths — O(n^2) complexity. Developers skip this optimization or implement it incorrectly.
|
||||
|
||||
**Consequences:** Players stare at a board with no solution, unsure if they're missing something or the game is broken.
|
||||
|
||||
**Prevention:**
|
||||
1. Implement efficient dead-end check: for each tile, check if ANY matching tile has a valid path
|
||||
2. Cache results and re-check only when tiles are cleared
|
||||
3. When dead-end detected, offer: shuffle remaining tiles, auto-solve hint, or graceful game-over
|
||||
|
||||
**Detection:** Player inactivity timeout; manual testing; analytics showing players abandoning mid-game
|
||||
|
||||
**Phase to address:** Phase 2 (Board Generation) or Phase 3 (Polish & UX)
|
||||
|
||||
---
|
||||
|
||||
### Pitfall 4: Grid Coordinate System Confusion
|
||||
|
||||
**What goes wrong:** Off-by-one errors, inverted row/column indexing, or mismatched coordinate systems between rendering, logic, and input handling.
|
||||
|
||||
**Why it happens:** Grids seem simple but have multiple valid coordinate conventions (0-indexed vs 1-indexed, row-major vs column-major, screen vs grid coordinates).
|
||||
|
||||
**Consequences:** Clicks register on wrong tiles, path visualization is offset, tiles clear in wrong positions. Debugging nightmare.
|
||||
|
||||
**Prevention:**
|
||||
1. Choose ONE coordinate system and document it clearly
|
||||
2. Create helper functions for coordinate conversion (screen-to-grid, grid-to-screen)
|
||||
3. Use consistent naming: (row, col) or (x, y) — never mix
|
||||
4. Add visual debugging to show grid coordinates on hover during development
|
||||
|
||||
**Detection:** Clicks feel "off"; tiles highlight incorrectly; path drawing is misaligned
|
||||
|
||||
**Phase to address:** Phase 1 (Core Matching Logic)
|
||||
|
||||
---
|
||||
|
||||
## Moderate Pitfalls
|
||||
|
||||
### Pitfall 5: Poor Visual Feedback for Connections
|
||||
|
||||
**What goes wrong:** Players click matching tiles but see no indication of WHY a match failed or succeeded. No path visualization, no highlight, no animation.
|
||||
|
||||
**Why it happens:** Developers focus on logic first, plan to "add polish later," but core feedback is essential for the game to feel playable.
|
||||
|
||||
**Prevention:**
|
||||
1. From the start, draw the connecting path (even as a simple line) when a match succeeds
|
||||
2. Show a visual indicator (shake, red flash) when a match fails
|
||||
3. Highlight selected tiles clearly
|
||||
|
||||
**Detection:** Playtesters ask "did that work?" or "why didn't those match?"
|
||||
|
||||
**Phase to address:** Phase 1 (Core Matching Logic)
|
||||
|
||||
---
|
||||
|
||||
### Pitfall 6: Responsive Grid Scaling Issues
|
||||
|
||||
**What goes wrong:** Grid looks fine on desktop but tiles become too small to click on mobile, or the grid overflows the viewport.
|
||||
|
||||
**Why it happens:** Fixed pixel sizes, aspect ratio assumptions, or not testing on actual mobile devices.
|
||||
|
||||
**Prevention:**
|
||||
1. Calculate tile size based on viewport dimensions and grid size
|
||||
2. Maintain minimum touch target size (44px recommended)
|
||||
3. Test on multiple screen sizes early
|
||||
4. Consider landscape vs portrait orientations
|
||||
|
||||
**Detection:** Manual testing on mobile; tiles hard to click on phone
|
||||
|
||||
**Phase to address:** Phase 3 (Polish & UX)
|
||||
|
||||
---
|
||||
|
||||
### Pitfall 7: Touch vs Mouse Input Handling
|
||||
|
||||
**What goes wrong:** Game works with mouse clicks but not touch taps, or vice versa. Double-tap zooms the page instead of selecting a tile.
|
||||
|
||||
**Why it happens:** Touch and mouse events are different; mobile browsers have default touch behaviors that interfere.
|
||||
|
||||
**Prevention:**
|
||||
1. Use pointer events (unified) or handle both touch and mouse explicitly
|
||||
2. Call `preventDefault()` on touch events to avoid double-tap zoom
|
||||
3. Handle touch latency and accidental multi-touch
|
||||
|
||||
**Detection:** Game unplayable on mobile devices
|
||||
|
||||
**Phase to address:** Phase 3 (Polish & UX)
|
||||
|
||||
---
|
||||
|
||||
### Pitfall 8: Performance Degradation with Large Boards
|
||||
|
||||
**What goes wrong:** Path-finding becomes slow on larger grids (10x10+), causing lag when checking for valid moves.
|
||||
|
||||
**Why it happens:** Naive path-finding is O(n*m) per pair check, and dead-end detection checks all pairs.
|
||||
|
||||
**Prevention:**
|
||||
1. Optimize path-finding with early termination
|
||||
2. Use spatial partitioning for large boards
|
||||
3. Cache path-finding results until board state changes
|
||||
4. For v1, limit board size to reasonable dimensions (8x8 or smaller)
|
||||
|
||||
**Detection:** Noticeable delay after clicking tiles; browser dev tools show high CPU usage
|
||||
|
||||
**Phase to address:** Phase 1 (Core Matching Logic)
|
||||
|
||||
---
|
||||
|
||||
## Minor Pitfalls
|
||||
|
||||
### Pitfall 9: Tile Asset Loading Issues
|
||||
|
||||
**What goes wrong:** Game displays before tile images load, shows broken images, or layout shifts as images load.
|
||||
|
||||
**Prevention:** Preload all tile assets before showing game; use placeholder dimensions; lazy-load only if necessary
|
||||
|
||||
**Phase to address:** Phase 3 (Polish & UX)
|
||||
|
||||
---
|
||||
|
||||
### Pitfall 10: No Win Condition Handling
|
||||
|
||||
**What goes wrong:** Player clears all tiles but game doesn't recognize victory — no celebration, no "you win" message.
|
||||
|
||||
**Prevention:** Check if tile count === 0; trigger win state; display victory message
|
||||
|
||||
**Phase to address:** Phase 2 (Board Generation)
|
||||
|
||||
---
|
||||
|
||||
## Technical Debt Patterns
|
||||
|
||||
| Shortcut | Immediate Benefit | Long-term Cost | When Acceptable |
|
||||
|----------|-------------------|----------------|-----------------|
|
||||
| Skip path visualization | Ship faster | Players confused why matches fail | Never — essential for core loop |
|
||||
| No dead-end detection | Simpler code | Players get stuck unfairly | Never for v1 — include basic detection |
|
||||
| Hardcode board layout | Quick prototype | Can't generate varied levels | Acceptable for proof-of-concept only |
|
||||
| Fixed grid size | Simpler rendering | Can't adjust difficulty | Acceptable for v1 (one level) |
|
||||
| No animations | Less code | Game feels lifeless | Acceptable for MVP, add before release |
|
||||
|
||||
## Integration Gotchas
|
||||
|
||||
| Integration | Common Mistake | Correct Approach |
|
||||
|-------------|----------------|------------------|
|
||||
| Browser events | Not preventing default touch behavior | Call `preventDefault()` on touchstart/touchend |
|
||||
| Canvas rendering | Not clearing canvas between frames | Clear before redraw, or track dirty regions |
|
||||
| Responsive layout | Using fixed pixel values | Use viewport units or calculated percentages |
|
||||
|
||||
## Performance Traps
|
||||
|
||||
| Trap | Symptoms | Prevention | When It Breaks |
|
||||
|------|----------|------------|----------------|
|
||||
| O(n^2) dead-end check every frame | Game freezes on larger boards | Check only on tile clear; cache results | 8x8 grid with naive implementation |
|
||||
| Re-rendering entire grid on every click | High CPU, battery drain | Track dirty tiles, re-render only changed | Any grid size with poor implementation |
|
||||
| Large tile images | Slow initial load, memory pressure | Optimize images, use spritesheets | 50+ unique tile images |
|
||||
|
||||
## Security Mistakes
|
||||
|
||||
| Mistake | Risk | Prevention |
|
||||
|---------|------|------------|
|
||||
| N/A | This is a client-side game with no backend or user data | Standard web security practices sufficient |
|
||||
|
||||
## UX Pitfalls
|
||||
|
||||
| Pitfall | User Impact | Better Approach |
|
||||
|---------|-------------|-----------------|
|
||||
| No feedback on failed match | User thinks game is broken | Visual shake/red flash on invalid selection |
|
||||
| No path visualization | User doesn't understand why match worked | Draw connecting lines (even briefly) |
|
||||
| Tiny tiles on mobile | Frustrating, inaccurate clicks | Calculate tile size for touch targets |
|
||||
| No indication of selected tile | User forgets first selection | Clear highlight/pulse on selected tile |
|
||||
| Instant tile removal | Feels abrupt, unsatisfying | Brief animation before removal |
|
||||
|
||||
## "Looks Done But Isn't" Checklist
|
||||
|
||||
- [ ] **Path-finding:** Often missing edge cases (paths along board edge, through cleared areas) — verify with unit tests covering all path types
|
||||
- [ ] **Dead-end detection:** Often missing entirely or incorrectly implemented — verify by manually creating unsolvable board and checking detection triggers
|
||||
- [ ] **Win condition:** Often forgotten — verify game recognizes when all tiles cleared
|
||||
- [ ] **Touch input:** Often works on desktop but not mobile — verify on actual mobile device
|
||||
- [ ] **Responsive grid:** Often breaks on small screens — verify on multiple viewport sizes
|
||||
|
||||
## Recovery Strategies
|
||||
|
||||
| Pitfall | Recovery Cost | Recovery Steps |
|
||||
|---------|---------------|----------------|
|
||||
| Incorrect path-finding | HIGH | Rewrite path algorithm; add comprehensive unit tests; may have shipped broken game |
|
||||
| Unsolvable board generation | MEDIUM | Add solvability validation; implement shuffle feature; may need to explain to players |
|
||||
| Dead-end detection failure | MEDIUM | Implement detection; add shuffle/hint features; moderate refactor |
|
||||
| Grid coordinate confusion | HIGH | Refactor all coordinate handling; find and fix all conversions; high regression risk |
|
||||
| Poor visual feedback | LOW | Add animations/highlights; doesn't affect core logic |
|
||||
|
||||
## Phase-Specific Warnings
|
||||
|
||||
| Phase Topic | Likely Pitfall | Mitigation |
|
||||
|-------------|---------------|------------|
|
||||
| Core matching logic | Path-finding edge cases | Exhaustive unit tests; visualize paths during development |
|
||||
| Board generation | Unsolvable boards | Generate from solved state backward; validate solvability |
|
||||
| Input handling | Touch vs mouse differences | Use pointer events; test on mobile early |
|
||||
| Polish & UX | Missing visual feedback | Implement path visualization from start (not as "polish") |
|
||||
| Responsive design | Grid too small on mobile | Calculate tile sizes dynamically; test on actual devices |
|
||||
|
||||
## Sources
|
||||
|
||||
- Domain knowledge from tile-matching game development patterns
|
||||
- Common path-finding algorithm edge cases (A*/BFS adaptations for grid-based pathfinding with turn limits)
|
||||
- Mobile web game development best practices (touch handling, responsive design)
|
||||
- Classic tile-matching games (Pikachu Kawai, Onet Connect) as reference implementations
|
||||
|
||||
**Note:** Web research was attempted but limited due to access restrictions. This document relies primarily on domain knowledge. Consider validating key algorithmic approaches against established implementations.
|
||||
|
||||
---
|
||||
*Pitfalls research for: Pikachu Match (tile-matching puzzle game)*
|
||||
*Researched: 2026-03-10*
|
||||
@@ -0,0 +1,173 @@
|
||||
# Stack Research: Web-Based Tile-Matching Puzzle Game
|
||||
|
||||
**Domain:** Web-based 2D puzzle game (tile-matching)
|
||||
**Researched:** 2026-03-10
|
||||
**Confidence:** HIGH
|
||||
|
||||
## Recommended Stack
|
||||
|
||||
### Core Technologies
|
||||
|
||||
| Technology | Version | Purpose | Why Recommended |
|
||||
|------------|---------|---------|-----------------|
|
||||
| **Vite** | 7.3.x | Build tool & dev server | Fastest HMR, native TypeScript support, minimal config. For a simple puzzle game, Vite's instant feedback loop accelerates development significantly. |
|
||||
| **TypeScript** | 5.x | Type safety | Prevents runtime errors in game logic (path-finding algorithm, tile state). The path-finding algorithm with 3-turn constraint benefits from strong typing. |
|
||||
| **HTML5 Canvas** | Native | 2D rendering | Sufficient for tile-matching game complexity. No framework overhead. Direct pixel control for smooth animations. Browser-native, zero dependencies. |
|
||||
| **Vanilla JS/TS** | ES2022+ | Game logic | No framework needed for this scope. Tile-matching games have simple state (grid array, selected tiles, score). Keeping it framework-free reduces bundle size and debugging surface. |
|
||||
|
||||
### Supporting Libraries
|
||||
|
||||
| Library | Version | Purpose | When to Use |
|
||||
|---------|---------|---------|-------------|
|
||||
| **none required** | - | - | For v1 minimal scope, vanilla Canvas is sufficient |
|
||||
|
||||
**Optional (add only if needed):**
|
||||
|
||||
| Library | Version | Purpose | When to Use |
|
||||
|---------|---------|---------|-------------|
|
||||
| **howler.js** | 2.2.x | Audio | If adding sound effects later (currently out of scope) |
|
||||
| **zustand** | 5.x | State management | If game state becomes complex (multiple screens, settings) |
|
||||
|
||||
### Development Tools
|
||||
|
||||
| Tool | Purpose | Notes |
|
||||
|------|---------|-------|
|
||||
| **Vite** | Dev server, build, HMR | Single tool handles all dev needs |
|
||||
| **tsc** | TypeScript compiler | Configured via tsconfig.json |
|
||||
| **ESLint** | Code quality | Optional but recommended for consistency |
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Create project with Vite + TypeScript
|
||||
npm create vite@latest pikachu-match -- --template vanilla-ts
|
||||
|
||||
# Navigate to project
|
||||
cd pikachu-match
|
||||
|
||||
# Install dependencies (minimal for v1)
|
||||
npm install
|
||||
|
||||
# Optional: Add ESLint
|
||||
npm install -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser
|
||||
|
||||
# Optional: Add sound library later
|
||||
# npm install howler
|
||||
```
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
| Recommended | Alternative | When to Use Alternative |
|
||||
|-------------|-------------|-------------------------|
|
||||
| **Vanilla Canvas** | **Phaser 3.90.x** | Use Phaser if: adding physics, particle effects, complex animations, multiple game scenes, or planning to expand significantly beyond v1 scope |
|
||||
| **Vanilla Canvas** | **PixiJS 8.x** | Use PixiJS if: needing WebGL/WebGPU for 1000+ sprites, complex visual effects, or planning graphics-intensive features |
|
||||
| **Vite** | **Parcel** | Use Parcel if: want zero-config (Vite requires minimal config but Parcel is truly zero-config) |
|
||||
| **TypeScript** | **JavaScript** | Use vanilla JS if: rapid prototyping only, team unfamiliar with TypeScript |
|
||||
|
||||
## What NOT to Use
|
||||
|
||||
| Avoid | Why | Use Instead |
|
||||
|-------|-----|-------------|
|
||||
| **React/Vue/Svelte** | DOM-based frameworks add unnecessary overhead for canvas games. Virtual DOM diffing is wasted when rendering to Canvas. Game loop pattern doesn't fit component model well. | Vanilla JS/TS with direct Canvas API |
|
||||
| **Game engines (Unity, Godot)** | Massive overkill for a 2D tile puzzle. Large bundle sizes, complex build pipeline. Web export adds 10MB+ overhead. | HTML5 Canvas (native browser API) |
|
||||
| **Webpack** | Slower dev server, complex config. Vite provides better DX in 2026. | Vite 7.x |
|
||||
| **Create React App** | Deprecated. React team recommends Vite-based alternatives. | Vite directly |
|
||||
| **jQuery** | Outdated for modern projects. No value for Canvas-based games. | Vanilla DOM API (minimal DOM interaction anyway) |
|
||||
| **Three.js** | 3D library — unnecessary for 2D tile game. Adds 500KB+ to bundle. | HTML5 Canvas (2D context) |
|
||||
| **Full game frameworks for simple games** | Phaser/PixiJS add learning curve and bundle size for features you won't use in v1. | Start with Canvas, add framework later if complexity grows |
|
||||
|
||||
## Stack Patterns by Variant
|
||||
|
||||
**If v1 scope expands to include animations/particles:**
|
||||
- Add Phaser 3.90.x
|
||||
- Because: Phaser's animation system, particle emitter, and scene management become valuable
|
||||
- Migration path: Keep game logic separate, swap rendering layer
|
||||
|
||||
**If targeting mobile-first with touch gestures:**
|
||||
- Add pointer event handling (native Canvas supports touch)
|
||||
- Consider adding hammer.js for complex gestures (not needed for simple tap-to-select)
|
||||
|
||||
**If adding save/load functionality:**
|
||||
- Use localStorage for v1 (no backend)
|
||||
- Add zustand for state management if state becomes complex
|
||||
|
||||
**If adding multiplayer:**
|
||||
- This requires significant architecture change (out of scope for v1)
|
||||
- Would need: WebSocket server, state synchronization, conflict resolution
|
||||
|
||||
## Version Compatibility
|
||||
|
||||
| Package | Compatible With | Notes |
|
||||
|---------|-----------------|-------|
|
||||
| Vite 7.x | Node.js 20.x+ | Requires ESM modules |
|
||||
| TypeScript 5.x | Vite 7.x | Vite has native TS support |
|
||||
| Canvas API | All modern browsers | IE11 not supported (irrelevant in 2026) |
|
||||
|
||||
## Bundle Size Expectations
|
||||
|
||||
| Approach | Minified | Gzipped | Notes |
|
||||
|----------|----------|---------|-------|
|
||||
| Vanilla Canvas + Vite | ~5KB | ~2KB | Your code only |
|
||||
| With Phaser | ~250KB | ~80KB | Framework overhead |
|
||||
| With PixiJS | ~200KB | ~65KB | Renderer overhead |
|
||||
| With React + Canvas | ~150KB | ~50KB | React runtime + your code |
|
||||
|
||||
**For Pikachu Match v1:** Target <10KB gzipped (vanilla approach).
|
||||
|
||||
## Architecture Notes
|
||||
|
||||
### Game Loop Pattern
|
||||
```typescript
|
||||
// Standard game loop - no framework needed
|
||||
function gameLoop(timestamp: number) {
|
||||
update(timestamp - lastTime);
|
||||
render(ctx);
|
||||
lastTime = timestamp;
|
||||
requestAnimationFrame(gameLoop);
|
||||
}
|
||||
```
|
||||
|
||||
### State Structure (Minimal)
|
||||
```typescript
|
||||
interface GameState {
|
||||
grid: Tile[][]; // 2D array of tiles
|
||||
selectedTile: Position | null;
|
||||
score: number;
|
||||
isAnimating: boolean;
|
||||
}
|
||||
|
||||
interface Tile {
|
||||
id: number;
|
||||
pokemonType: number; // Which Pokemon (for matching)
|
||||
cleared: boolean;
|
||||
}
|
||||
```
|
||||
|
||||
### Path-Finding Algorithm
|
||||
- BFS or A* variant for finding paths with max 3 segments
|
||||
- Well-documented algorithm, no library needed
|
||||
- Core complexity: O(n*m) where n,m are grid dimensions
|
||||
|
||||
## Confidence Assessment
|
||||
|
||||
| Recommendation | Confidence | Reason |
|
||||
|----------------|------------|--------|
|
||||
| Vite 7.x | HIGH | Industry standard in 2026, verified via npm |
|
||||
| Vanilla Canvas | HIGH | Sufficient for v1 scope, minimal dependencies |
|
||||
| TypeScript 5.x | HIGH | Standard for maintainable codebases |
|
||||
| Avoid React | HIGH | Clear architectural mismatch for Canvas games |
|
||||
| Phaser as alternative | MEDIUM | Good option if scope expands, but adds complexity |
|
||||
| PixiJS as alternative | MEDIUM | Good for graphics-heavy games, overkill for v1 |
|
||||
|
||||
## Sources
|
||||
|
||||
- **npm/package/phaser** — Version 3.90.0, features, bundle size (HIGH confidence)
|
||||
- **npm/package/vite** — Version 7.3.1, features (HIGH confidence)
|
||||
- **pixijs.com** — Version 8.x, installation, features (HIGH confidence)
|
||||
- **MDN Web Docs (Canvas API)** — Standard reference for Canvas rendering (HIGH confidence)
|
||||
- **Phaser documentation** — Framework capabilities, when to use (MEDIUM confidence - official docs)
|
||||
- **Vite documentation** — Build tool features, TypeScript support (HIGH confidence)
|
||||
|
||||
---
|
||||
*Stack research for: Web-based tile-matching puzzle game*
|
||||
*Researched: 2026-03-10*
|
||||
@@ -0,0 +1,196 @@
|
||||
# Project Research Summary
|
||||
|
||||
**Project:** Pikachu Match
|
||||
**Domain:** Web-based tile-matching puzzle game (Onet Connect / Pikachu Kawai style)
|
||||
**Researched:** 2026-03-10
|
||||
**Confidence:** HIGH
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Pikachu Match is a 2D tile-matching puzzle game where players connect matching Pokemon tiles using paths with no more than 3 straight lines (2 turns). This is a well-established genre with proven patterns - the core mechanic has been validated across dozens of successful implementations (Onet Connect, Pikachu Kawai, various mobile apps).
|
||||
|
||||
Research strongly recommends a minimal, vanilla approach: **Vite + TypeScript + HTML5 Canvas** with no game framework. The scope is small enough that Phaser or PixiJS would add unnecessary complexity and bundle size. The path-finding algorithm (3-line constraint) is the primary technical challenge - it requires careful implementation with exhaustive unit tests covering edge cases like boundary paths and paths through cleared tiles.
|
||||
|
||||
Key risks include incorrect path-finding logic (breaks game feel), unsolvable board generation (frustrates players), and dead-end detection failures (players get stuck). All three can be mitigated through proper algorithm design, comprehensive testing, and implementing the shuffle recovery feature from the start.
|
||||
|
||||
## Key Findings
|
||||
|
||||
### Recommended Stack
|
||||
|
||||
Use a minimal, framework-free approach optimized for fast development and tiny bundle size.
|
||||
|
||||
**Core technologies:**
|
||||
- **Vite 7.3.x** (build tool & dev server) - Fastest HMR, minimal config, native TypeScript support
|
||||
- **TypeScript 5.x** (type safety) - Prevents runtime errors in path-finding algorithm and game state
|
||||
- **HTML5 Canvas** (2D rendering) - Native browser API, zero dependencies, direct pixel control for smooth animations
|
||||
- **Vanilla JS/TS** (game logic) - No framework needed for this scope; keeping it framework-free reduces bundle size
|
||||
|
||||
**Target bundle size:** <10KB gzipped (vanilla approach)
|
||||
|
||||
**Avoid:** React/Vue/Svelte (DOM-based frameworks add unnecessary overhead for Canvas games), Phaser/PixiJS for v1 (add 80-250KB overhead, only needed if scope expands significantly), game engines like Unity/Godot (massive overkill for 2D tile puzzle)
|
||||
|
||||
### Expected Features
|
||||
|
||||
**Must have (table stakes):**
|
||||
- Grid of paired tiles (even count, matched pairs) - Core mechanic
|
||||
- Click-to-select two matching tiles - Standard interaction
|
||||
- Path validation (max 3 straight lines / 2 turns) - Core rule
|
||||
- Matched tiles disappear with animation - Visual feedback
|
||||
- Score display - Performance tracking
|
||||
- Timer with lose condition - Time pressure
|
||||
- Win condition (board cleared) - Success state
|
||||
- No moves detection + shuffle - Recovery mechanism
|
||||
- Responsive grid (desktop + mobile) - Platform requirement
|
||||
|
||||
**Should have (competitive):**
|
||||
- Hint system (limited uses) - Prevents frustration
|
||||
- Visual connection preview - Helps learn rules
|
||||
- Local high score (localStorage) - Persistence without backend
|
||||
- Sound effects - Audio satisfaction
|
||||
- Tutorial overlay for first-time players - Onboarding
|
||||
|
||||
**Defer (v2+):**
|
||||
- Multiple tile themes - Visual variety
|
||||
- Level progression with difficulty scaling - Long-term engagement
|
||||
- Combo multipliers - Depth for skilled players
|
||||
- Dark/light theme toggle - Accessibility
|
||||
- Keyboard controls - Accessibility
|
||||
|
||||
### Architecture Approach
|
||||
|
||||
Follow a layered architecture with clear separation of concerns: Presentation Layer (Renderer, Animator, UI Overlay), Game Logic Layer (Game Loop, Input Handler, PathFinder, Grid Manager, Score System), State Layer (Idle, Selected, Matching, GameOver states), and Data Layer (Tile Model, Game State, Config).
|
||||
|
||||
**Major components:**
|
||||
1. **Game Loop** - Orchestrates update/render cycle using requestAnimationFrame with delta time
|
||||
2. **Grid Manager** - Owns tile grid, handles tile state, generates layouts (2D array of tile objects)
|
||||
3. **PathFinder** - Validates connections using BFS/DFS with turn counting (3-line algorithm)
|
||||
4. **Input Handler** - Captures clicks/touches, translates to grid coordinates
|
||||
5. **Renderer** - Draws grid, tiles, connection lines, animations using Canvas 2D API
|
||||
6. **State Machine** - Manages game states (idle, selected, matching, animating, game over) with explicit transitions
|
||||
7. **Score System** - Tracks points, combos, game progress
|
||||
8. **Animation Manager** - Handles tile disappear, connection line, UI effects
|
||||
|
||||
**Key patterns:** Game Loop (frame-based updates), State Machine (discrete game states), Observer/Event Emitter (loose coupling between components)
|
||||
|
||||
### Critical Pitfalls
|
||||
|
||||
1. **Incorrect Path-Finding Algorithm Implementation** - Implement path check as: straight line (0 turns), one-turn path (L-shape), two-turn path (U-shape or Z-shape). Test exhaustively with unit tests covering all path types and edge cases.
|
||||
|
||||
2. **Unsolvable Board Generation** - Generate boards by placing pairs in reverse (start with empty board, add matched pairs in positions that are guaranteed connectable) OR validate solvability after random generation and regenerate if unsolvable.
|
||||
|
||||
3. **Dead-End Detection Failure** - Implement efficient dead-end check: for each tile, check if ANY matching tile has a valid path. Cache results and re-check only when tiles are cleared. When dead-end detected, offer shuffle.
|
||||
|
||||
4. **Grid Coordinate System Confusion** - Choose ONE coordinate system and document it clearly. Create helper functions for coordinate conversion (screen-to-grid, grid-to-screen). Use consistent naming: (row, col) or (x, y) - never mix.
|
||||
|
||||
5. **Poor Visual Feedback for Connections** - From the start, draw the connecting path (even as a simple line) when a match succeeds. Show a visual indicator (shake, red flash) when a match fails.
|
||||
|
||||
## Implications for Roadmap
|
||||
|
||||
Based on research, suggested phase structure:
|
||||
|
||||
### Phase 1: Core Foundation
|
||||
**Rationale:** These components have no dependencies and everything else builds on them. Establishes the fundamental architecture patterns.
|
||||
**Delivers:** Project structure, configuration, event system, basic game loop
|
||||
**Addresses:** Grid coordinate system (pitfall #4)
|
||||
**Components:** GameConfig/Constants, EventEmitter, GameLoop, Tile model
|
||||
|
||||
### Phase 2: Grid and Input
|
||||
**Rationale:** Establishes the game board and basic interaction. Need grid before implementing matching logic.
|
||||
**Delivers:** Rendered grid with tiles, basic click/touch input handling
|
||||
**Uses:** Vite + TypeScript + Canvas (from STACK.md)
|
||||
**Implements:** Grid Manager, InputHandler, basic Renderer
|
||||
**Addresses:** Responsive grid scaling (pitfall #6), Touch vs mouse input (pitfall #7)
|
||||
|
||||
### Phase 3: Core Matching Mechanics
|
||||
**Rationale:** Implements the core game loop - the path-finding algorithm is the heart of the game and most complex component.
|
||||
**Delivers:** Playable game where tiles can be matched and removed
|
||||
**Components:** PathFinder, SelectedState, MatchingState, MatchEngine
|
||||
**Addresses:** Incorrect path-finding (pitfall #1), Poor visual feedback (pitfall #5)
|
||||
**Critical:** Exhaustive unit tests for path-finding covering all edge cases
|
||||
|
||||
### Phase 4: Game State Management
|
||||
**Rationale:** With core mechanics working, add proper state transitions, win/lose conditions, and score tracking.
|
||||
**Delivers:** Complete game loop with all states, scoring system
|
||||
**Components:** StateMachine (full), IdleState, AnimatingState, ScoreSystem, MoveDetector, GameOverState
|
||||
**Addresses:** Dead-end detection failure (pitfall #3)
|
||||
|
||||
### Phase 5: Board Generation and Recovery
|
||||
**Rationale:** Implement proper board generation with solvability validation and shuffle feature for dead-end recovery.
|
||||
**Delivers:** Solvable boards, shuffle feature when stuck
|
||||
**Components:** Board generation logic, Shuffle utility, No moves detection
|
||||
**Addresses:** Unsolvable board generation (pitfall #2)
|
||||
|
||||
### Phase 6: Polish and UX
|
||||
**Rationale:** Enhance the core loop with animations, hints, and responsive design refinements.
|
||||
**Delivers:** Smooth animations, hint system, tutorial, responsive design tested on multiple devices
|
||||
**Components:** AnimationManager, HintSystem, tutorial overlay, responsive grid refinements
|
||||
**Addresses:** Performance degradation (pitfall #8), Tile asset loading (pitfall #9)
|
||||
|
||||
### Phase Ordering Rationale
|
||||
|
||||
- **Foundation first:** Config, events, and game loop are dependencies for everything else
|
||||
- **Grid before matching:** Need a visible board before implementing interaction logic
|
||||
- **Path-finding early:** The 3-line algorithm is the most complex component and needs extensive testing
|
||||
- **State management after mechanics:** State transitions only make sense once matching works
|
||||
- **Board generation after state:** Need game-over detection to validate solvability
|
||||
- **Polish last:** Animations and hints enhance but don't change core functionality
|
||||
|
||||
This ordering ensures each phase builds on working components from previous phases, minimizing rework and enabling early testing of critical path-finding logic.
|
||||
|
||||
### Research Flags
|
||||
|
||||
Phases likely needing deeper research during planning:
|
||||
- **Phase 3 (Core Matching Mechanics):** Path-finding algorithm with 3-line constraint has nuanced edge cases - consider researching established implementations or algorithm references
|
||||
- **Phase 5 (Board Generation):** Solvability validation is non-trivial - may need to research constraint satisfaction or backtracking algorithms
|
||||
|
||||
Phases with standard patterns (skip research-phase):
|
||||
- **Phase 1 (Core Foundation):** Well-documented patterns for game loop, event emitter
|
||||
- **Phase 2 (Grid and Input):** Standard Canvas rendering and input handling
|
||||
- **Phase 6 (Polish):** Animation and responsive design are well-documented web development patterns
|
||||
|
||||
## Confidence Assessment
|
||||
|
||||
| Area | Confidence | Notes |
|
||||
|------|------------|-------|
|
||||
| Stack | HIGH | Industry standard in 2026, verified via npm, clear rationale for minimal approach |
|
||||
| Features | MEDIUM | Based on competitor analysis and domain knowledge; web research limited |
|
||||
| Architecture | HIGH | Well-documented game development patterns (Game Loop, State Machine, Component) |
|
||||
| Pitfalls | MEDIUM | Based on domain knowledge; web research was limited but pitfalls align with known game development challenges |
|
||||
|
||||
**Overall confidence:** HIGH
|
||||
|
||||
The core technical approach (Vite + TypeScript + Canvas) is well-established and low-risk. The path-finding algorithm is the primary technical challenge but has documented patterns. The main uncertainty is in feature prioritization and competitive landscape, which should be validated through playtesting.
|
||||
|
||||
### Gaps to Address
|
||||
|
||||
- **Path-finding algorithm implementation details:** While BFS/DFS with turn counting is the standard approach, specific edge cases (paths along board boundaries, through cleared areas) need careful implementation. Plan to create comprehensive unit tests during Phase 3.
|
||||
|
||||
- **Board solvability validation:** The research recommends generating boards backward or validating after generation, but specific algorithms for either approach need investigation during Phase 5 planning.
|
||||
|
||||
- **Mobile performance optimization:** Research suggests dirty rectangle rendering for large grids, but specific implementation details should be addressed if performance issues arise during testing.
|
||||
|
||||
- **Touch input edge cases:** Research mentions handling touch latency and accidental multi-touch, but specific strategies should be refined during mobile testing in Phase 6.
|
||||
|
||||
## Sources
|
||||
|
||||
### Primary (HIGH confidence)
|
||||
- **npm/package/phaser** - Version 3.90.0, features, bundle size
|
||||
- **npm/package/vite** - Version 7.3.1, features
|
||||
- **pixijs.com** - Version 8.x, installation, features
|
||||
- **MDN Web Docs (Canvas API)** - Standard reference for Canvas rendering
|
||||
- **MDN Game Development** - Game anatomy and game loop patterns
|
||||
- **Game Programming Patterns by Robert Nystrom** - Game Loop, Component, State patterns
|
||||
- **Vite documentation** - Build tool features, TypeScript support
|
||||
|
||||
### Secondary (MEDIUM confidence)
|
||||
- **Onet Connect Classic - CrazyGames** - Feature analysis: timer, hints, shuffle, themes, levels
|
||||
- **Phaser documentation** - Framework capabilities, when to use
|
||||
- **Domain knowledge** - Tile-matching game development patterns, path-finding algorithms
|
||||
|
||||
### Tertiary (LOW confidence - needs validation)
|
||||
- **Pikachu Kawai reference** - Classic implementation patterns (inferred from domain knowledge)
|
||||
- **Mobile web game development** - Touch handling, responsive design (general best practices)
|
||||
|
||||
---
|
||||
*Research completed: 2026-03-10*
|
||||
*Ready for roadmap: yes*
|
||||
Reference in New Issue
Block a user