Files
ttt/docs/PLAN.md
T
2026-09-23 16:31:05 +03:00

180 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Tic-Tac-Toe vs CPU — Implementation Plan
A polished, mobile-friendly tic-tac-toe game (X vs O) playable in the browser against a
random-move CPU opponent. Pure HTML/CSS/JS — no build step, no dependencies.
Open `index.html` directly in a browser to play.
## 1. Project Structure
```
game1/
├── index.html # Page structure (board, scoreboard, status, overlay)
├── style.css # All styling: glassmorphism dark theme, animations
├── game.js # Game logic: state, win detection, CPU, scoring, FX
└── docs/
├── PLAN.md # This document
└── mockup.svg # UI mockup (open in a browser to view)
```
## 2. Visual Design
Research (Dribbble/Figma/CodePen examples) shows the current popular style for
tic-tac-toe: **dark glassmorphism with neon accents**, frosted panels, soft glows,
and confetti celebrations on wins.
- **Background**: deep gradient (dark navy → violet) with two soft blurred
colored blobs (cyan + magenta) for depth.
- **Panels**: frosted glass cards — `background: rgba(255,255,255,0.06)`,
`backdrop-filter: blur(14px)`, 1px translucent white border, soft shadow.
(Blur kept modest for mobile performance.)
- **Colors**:
- X (player) — neon cyan `#22d3ee`
- O (CPU) — neon pink/magenta `#f472b6`
- Text: white / muted gray
- **Typography**: system font stack, bold title, tabular numerals for scores.
- **Mockup**: see `docs/mockup.svg` (open in a browser) for the envisioned
look — dark glass panels, neon cyan X / pink O with glow, gradient title.
- **Layout (top → bottom)**:
1. Title: "Tic-Tac-Toe" with subtle gradient text
2. Scoreboard: three glass chips — You (X) · CPU (O) · Draws
3. Status bar: "Your turn" / "CPU is thinking…" / result text
4. Board: 3×3 grid of glass cells
5. Buttons: "New Game" (primary) and "Reset Scores" (ghost)
## 3. Mobile-Friendliness
- `<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">`
- Board width: `min(88vw, 340px)`; cells are large touch targets (≥ 72px on phones).
- `touch-action: manipulation` on buttons/cells to kill double-tap zoom delay.
- No hover-only interaction: hover glow is a desktop enhancement only; taps work
everywhere. Use `:active` press feedback.
- Layout uses flex column, centered, max-width 420px — looks like a mobile app
on desktop too.
- `user-select: none` on the board to avoid text selection while tapping fast.
- Test: 360px-wide viewport, fast repeated taps, orientation change.
## 4. Game Rules
- Standard 3×3 tic-tac-toe. Player is **X**, CPU is **O**.
- Player always starts the round with X (keeps it simple and predictable).
- Click/tap an empty cell to place your mark.
- CPU responds on a random empty cell after a **600 ms "thinking" delay**
(feels natural, shows the "CPU is thinking…" status).
- Win: 3 in a row (8 winning lines). Draw: board full with no winner.
- After a round ends, a result overlay appears; "Play Again" starts a fresh round
(board clears, scores persist).
## 5. Scoring
- Track **You**, **CPU**, and **Draws** across rounds.
- Persisted in `localStorage` (key `ttt-scores`) so scores survive reloads.
- "Reset Scores" button zeroes them (with a short confirm-less toast feedback).
- Score chips animate a quick pop when the value changes.
## 6. Game-Over Reactions
- **Winning line**: an SVG line is drawn across the three winning cells with a
stroke-dashoffset animation (draws itself in ~400 ms).
- **Result overlay**: frosted glass modal fades/scales in with:
- Win → "You Win! 🎉" + confetti burst (DOM particles, ~40 pieces, random
colors/velocities, fall + fade over ~1.8 s, then removed).
- Loss → "CPU Wins" + a subtle red-tinted shake of the board.
- Draw → "It's a Draw" + neutral pulse.
- Overlay has a single big "Play Again" button.
- Small micro-feedback during play:
- Marks pop in with a scale+fade animation (150 ms).
- Empty cells glow faintly on hover (desktop) and brighten on `:active`.
- Status bar text cross-fades on turn change; "CPU is thinking…" pulses.
## 7. JavaScript Architecture (game.js)
Single file, plain functions + one state object:
```
state = {
board: Array(9).fill(null), // null | 'X' | 'O'
turn: 'X', // 'X' = player, 'O' = CPU
gameOver: false,
scores: { you: 0, cpu: 0, draws: 0 }
}
```
Modules (sections in the file):
1. **DOM refs** — cells, status, score chips, overlay, buttons.
2. **Win detection** — `WIN_LINES` = 8 combos; `checkWinner(board)` returns
`{winner, line}` or `{winner: 'draw'}` or `null`.
3. **Player move** — `onCellTap(i)`: ignore if occupied/game over/CPU turn;
place X, render, check end; else schedule CPU.
4. **CPU move** — `cpuMove()`: after 600 ms, pick a random empty index,
place O, render, check end.
5. **Render** — `renderMark(i, mark)` (pop animation), `renderStatus()`,
`renderScores()`, `drawWinLine(line)` (SVG overlay on the board).
6. **Round end** — `endRound(result)`: update + persist scores, show overlay
with appropriate FX (confetti / shake / pulse).
7. **Confetti** — `burstConfetti()`: create N absolutely-positioned divs with
random transforms, animate via CSS transitions, remove after finish.
8. **Reset** — `newRound()` (clear board, player first), `resetScores()`.
9. **Init** — load scores from localStorage, build board DOM, bind events.
## 8. Implementation Steps
1. `index.html` — semantic structure, viewport meta, SVG defs for win line.
2. `style.css` — theme tokens (CSS custom properties), background, glass panels,
board grid, marks (X/O drawn with CSS or inline SVG for crispness),
animations (pop, pulse, shake, confetti fall), overlay, responsive tweaks.
3. `game.js` — implement sections 1–9 above.
4. Manual test pass:
- Win all 8 line types (play through scenarios).
- Draw scenario.
- Rapid tapping (no double placement, no CPU overlap).
- Scores persist across reload; reset works.
- 360px viewport: no overflow, big touch targets, no zoom on tap.
5. Polish: check animation smoothness on a mid-range phone if available.
## 9. Hosting the App
The app is three static files, so any static file server works. The goal is a
one-line start, no config files, no build step.
**Primary option — Python (already installed, zero setup):**
```bash
python3 -m http.server 8000
```
Run from the `game1/` folder. It binds to all network interfaces by default,
so the game is immediately reachable:
- **Same machine**: http://localhost:8000
- **Same network (LAN)**: http://\<machine-ip\>:8000
(find the IP with `hostname -I` or `ip addr`)
- **Internet**: forward port 8000 in the router/firewall, or put the machine
behind a reverse proxy. For public exposure, prefer caddy (see below) and
keep the raw port closed otherwise.
**Alternative — Caddy (nicest for internet exposure, auto-TLS with a domain):**
```bash
caddy file-server --root . --listen :8000
```
**Alternative — Node (if Python is unavailable):**
```bash
npx serve -l 8000
```
Notes:
- These dev servers are fine for LAN / home use. For a public internet
endpoint, use caddy behind a domain (it handles TLS automatically) and do
not expose the raw port to the internet with a bare dev server.
- No deploy step: the folder *is* the app — copy it anywhere and serve it.
## 10. Non-Goals (kept simple on purpose)
- No minimax / unbeatable AI (CPU is random, as requested).
- No sound effects, no multi-language support, no user-vs-user mode.
- No framework, no bundler — the game is three files.