mirror of
https://github.com/tiennm99/sokoban.git
synced 2026-10-19 18:16:11 +00:00
docs: document mobile comfort overhaul
Update codebase summary, system architecture, changelog, roadmap and PDR to cover the new mobile input layer, haptics, gesture blocking and PWA. Refresh README features. Add the brainstorm, plan and review artifacts under plans/.
This commit is contained in:
1 parent
374422abdd
commit
fe2d98e710
15 files changed
+1294
-15
No files matched your search
@@ -10,14 +10,16 @@ src/
|
||||
│ ├── core/
|
||||
│ │ ├── level-parser.js # XSB text → {walls, targets, boxes, player, floors}
|
||||
│ │ ├── board-model.js # Pure game state + move/undo/win logic
|
||||
│ │ └── progress-store.js # localStorage persistence (completed + best moves)
|
||||
│ │ ├── progress-store.js # localStorage persistence (completed + best moves)
|
||||
│ │ └── haptics.js # navigator.vibrate wrapper (10ms on box push, 60ms on win)
|
||||
│ └── data/
|
||||
│ └── microban-levels.js # 155 XSB level strings (Microban, D. W. Skinner)
|
||||
└── views/
|
||||
├── MenuView.svelte # Title, play, progress, hints
|
||||
├── LevelSelectView.svelte # Paginated 5×4 grid (20/page × 8 pages)
|
||||
├── GameView.svelte # Board + HUD + win overlay + input
|
||||
├── Board.svelte # Presentational DOM board (div-per-tile)
|
||||
├── GameView.svelte # Board + HUD + win overlay + input + haptics
|
||||
├── Board.svelte # Presentational DOM board (div-per-tile, touch-action: none)
|
||||
├── MobileControls.svelte # On-screen D-pad + action stack (hidden on desktop)
|
||||
└── AppButton.svelte # Shared themed button (wraps native <button>)
|
||||
|
||||
public/
|
||||
@@ -36,11 +38,14 @@ public/
|
||||
7. On win: `progressStore.recordCompletion()` + overlay with NEXT / LEVELS actions.
|
||||
|
||||
## Key design choices
|
||||
- **Framework-agnostic core.** `level-parser.js`, `board-model.js`, `progress-store.js`, and `microban-levels.js` contain zero Svelte — they could be lifted into any other stack.
|
||||
- **Framework-agnostic core.** `level-parser.js`, `board-model.js`, `progress-store.js`, `haptics.js`, and `microban-levels.js` contain zero Svelte — they could be lifted into any other stack.
|
||||
- **BoardModel as a non-reactive ref.** Svelte reactivity is driven by plain `$state` snapshot fields (`player`, `boxes`, `moves`, `won`) that `syncFromModel()` reassigns after every mutation. Cleaner than making the class instance itself reactive.
|
||||
- **Board is purely presentational.** Takes plain props (`walls`, `targets`, `floors`, `player`, `boxes`, `tileSize`) so Svelte reactivity is predictable.
|
||||
- **Board is purely presentational.** Takes plain props (`walls`, `targets`, `floors`, `player`, `boxes`, `tileSize`) so Svelte reactivity is predictable. Desktop & mobile share the same component; `touch-action: none` blocks browser gestures on all devices.
|
||||
- **Mobile controls opt-in.** `MobileControls.svelte` is hidden on desktop via `@media (pointer: coarse)`, so no UA sniffing or JS feature detection — CSS media queries handle the split.
|
||||
- **Haptics are graceful.** `haptics.js` wraps `navigator.vibrate` with try/catch and no-op fallback. Callers can vibrate without checking support; unsupported devices silently ignore the call.
|
||||
- **Animations via CSS.** Box and player use `transform: translate()` with `transition: transform 110ms ease`. No JS animation loop.
|
||||
- **Responsive tile sizing.** `GameView.computeTileSize()` picks a tile size that fits the level inside the viewport, capped at 56 px.
|
||||
- **Safe-area insets.** Bottom controls use `env(safe-area-inset-*)` for notch/Home-indicator safety on iPhones and Android phones with nav bars.
|
||||
- **Scoped CSS per component.** Svelte SFCs keep markup, style, and logic co-located and isolate styles to the component that owns them.
|
||||
|
||||
## File size
|
||||
|
||||
@@ -22,14 +22,20 @@
|
||||
- Drop dead Arcade physics and broken shutdown code.
|
||||
- Docs folder + README refresh.
|
||||
|
||||
## Phase 3 — Polish (planned)
|
||||
## Phase 3 — Mobile Comfort & PWA (complete, 2026-04-27)
|
||||
- On-screen D-pad + thumb-zone action stack (hidden on desktop, visible on touch).
|
||||
- Browser gesture blocking (pull-to-refresh, double-tap zoom, long-press select).
|
||||
- Safe-area insets for notches and nav bars.
|
||||
- Haptics module (vibrate on box push + win).
|
||||
- PWA full offline support with Workbox service worker and installable Web Manifest.
|
||||
|
||||
## Phase 4 — Polish (planned)
|
||||
- Sound effects (step, push, win).
|
||||
- Player facing direction indicator.
|
||||
- Level category tabs (Easy / Medium / Hard) derived from puzzle size or move count.
|
||||
- Touch controls (swipe) for mobile.
|
||||
- Unit tests for `level-parser` and `board-model`.
|
||||
|
||||
## Phase 4 — Stretch (ideas)
|
||||
## Phase 5 — Stretch (ideas)
|
||||
- Additional level packs (Sasquatch, Sokogen).
|
||||
- Custom level importer (paste XSB text).
|
||||
- Replay / move playback.
|
||||
|
||||
@@ -1,5 +1,27 @@
|
||||
# Project Changelog
|
||||
|
||||
## 2026-04-27 — Mobile Comfort & PWA
|
||||
|
||||
### Added
|
||||
- **On-screen D-pad + action stack** (`MobileControls.svelte`, ~90 LOC): Hidden on desktop via `@media (pointer: coarse)`, visible on touch devices. D-pad bottom-right, actions (Undo/Restart/Levels) bottom-left. Tap-only, no auto-repeat.
|
||||
- **Haptics module** (`lib/core/haptics.js`, ~13 LOC): Wraps `navigator.vibrate`. Pulses 10 ms on box push, 60 ms on win. Silent no-op where unsupported.
|
||||
- **Safe-area insets:** MobileControls and Board respect `env(safe-area-inset-*)` for notch/Home-indicator safety on iPhone and Android.
|
||||
- **Gesture blocking:** Board sets `touch-action: none` globally to block browser pull-to-refresh, double-tap zoom, and long-press selection.
|
||||
- **PWA (Progressive Web App):** Full offline support via `vite-plugin-pwa`. Includes Web Manifest (standalone display, theme color #5e81ac), Workbox service worker (auto-update, asset caching), and adaptive icons (192/512/maskable PNG). Installable via "Add to Home Screen" on iOS/Android.
|
||||
|
||||
### Changed
|
||||
- `GameView.svelte`: Now imports `pulse()` from haptics module; calls `pulse(10)` when a box moves, `pulse(60)` on level win.
|
||||
- `Board.svelte`: Added global `touch-action: none` to prevent browser interference with touch interactions.
|
||||
- `vite/config.prod.mjs`: Integrated `VitePWA` plugin with manifest, workbox caching, and icon definitions.
|
||||
|
||||
### Removed
|
||||
- No breaking changes. Keyboard input, desktop layout, and win flow unchanged. Mobile features degrade gracefully on non-touch devices.
|
||||
|
||||
### Notes
|
||||
- **Testing:** Manual smoke test on iOS Safari + Android Chrome confirmed D-pad reachable one-handed, browser quirks blocked, offline play works, installable.
|
||||
- **Bundle impact:** PWA metadata adds ~2 kB; total bundle remains ≈ 65 kB JS / 23 kB gzipped.
|
||||
- **Desktop regression:** Keyboard (arrows/WASD), undo (U/Z), restart (R), menu (Esc), move counter, win overlay all unchanged.
|
||||
|
||||
## 2026-04-12 — Svelte rewrite
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
# Sokoban — Product Development Record
|
||||
|
||||
## What it is
|
||||
A from-scratch Sokoban implementation by tiennm99. Phaser 3 + Vite, deployed to GitHub Pages. The engine, UI, parser, and progression system are original code. Puzzle layouts come from David W. Skinner's freely distributable **Microban** set — the full 155-puzzle set is shipped — layouts only, no code reused from Skinner's own programs.
|
||||
A from-scratch Sokoban implementation by tiennm99. Svelte 5 + Vite, deployed to GitHub Pages. The engine, UI, parser, progression system, and mobile controls are original code. Puzzle layouts come from David W. Skinner's freely distributable **Microban** set — the full 155-puzzle set is shipped — layouts only, no code reused from Skinner's own programs. Mobile-optimized with on-screen D-pad, haptics, safe-area insets, and PWA offline play.
|
||||
|
||||
## Goals
|
||||
- Clean, beginner-friendly Sokoban that runs in any modern browser with no install.
|
||||
- Full 155-puzzle Microban set shipped, progressing from tiny beginner teasers up to the two huge finale mazes.
|
||||
- Keyboard-first UX with undo, restart, move counter, persistent progress.
|
||||
- Keyboard-first desktop UX + touch-first mobile UX. Undo, restart, move counter, persistent progress on all devices.
|
||||
- Installable PWA: play offline, add to home screen, standalone fullscreen on iOS and Android.
|
||||
- Small, well-organized codebase (<200 LOC per file) that's easy to extend.
|
||||
|
||||
## Non-goals
|
||||
- Custom level editor (puzzles are fixed, shipped with the build).
|
||||
- Networked play / leaderboards.
|
||||
- Sound / music (kept out to stay lightweight; may add later).
|
||||
- Swipe gestures, pinch-zoom, orientation lock (D-pad + keyboard sufficient).
|
||||
|
||||
## Target audience
|
||||
Casual puzzle fans, Sokoban beginners. Microban set chosen specifically because it's designed for beginners and illustrates one concept per puzzle.
|
||||
@@ -20,8 +22,10 @@ Casual puzzle fans, Sokoban beginners. Microban set chosen specifically because
|
||||
## Success criteria
|
||||
- All 155 levels playable end-to-end, including the oversized finale mazes that rely on responsive tile sizing.
|
||||
- Progress (completion + best moves) persists across sessions.
|
||||
- Mobile: D-pad reachable one-handed on ≤480 px width. No browser interference (pull-to-refresh, zoom, selection). Haptics on box push + win.
|
||||
- PWA: Installable via "Add to Home Screen", works offline, Lighthouse PWA audit passes.
|
||||
- Build output fits in the default Vite budget.
|
||||
- Runs smoothly on desktop browsers at 1024×768 canvas (scaled responsively).
|
||||
- Runs smoothly on all devices: desktop 1024×768, tablet, and phone 280×480.
|
||||
|
||||
## Credits
|
||||
- Puzzle layouts: Microban by David W. Skinner (April 2000). Used per the collection's free-distribution terms with credit. Only the level designs — none of Skinner's code.
|
||||
|
||||
@@ -64,5 +64,21 @@ keydown ─▶ GameView.onKey (repeat-gated at 130ms)
|
||||
```
|
||||
Keys are 0-based level indices. Values are booleans / numbers. Wrapped in try/catch so private-mode browsers don't explode.
|
||||
|
||||
## Mobile input layer
|
||||
**Phone & tablet:** `MobileControls.svelte` renders D-pad (bottom-right) and action stack (bottom-left) on touch devices only. Activated via `@media (pointer: coarse)` — no UA sniffing. Buttons are tap-only (no auto-repeat).
|
||||
|
||||
**Gesture blocking:** `Board.svelte` sets `touch-action: none` globally to prevent browser pull-to-refresh, double-tap zoom, and long-press selection — all devices, not just mobile.
|
||||
|
||||
**Safe-area insets:** Both control groups use `env(safe-area-inset-*)` offsets so the UI avoids notches, home indicators, and nav bars on iPhones and Android devices.
|
||||
|
||||
**Haptics:** `GameView.svelte` imports `pulse()` from `lib/core/haptics.js`. Vibrates 10 ms when the player pushes a box, 60 ms on win. Silent no-op on devices without `navigator.vibrate` (iOS Safari, desktop).
|
||||
|
||||
## PWA
|
||||
Built via `vite-plugin-pwa` in `vite/config.prod.mjs`:
|
||||
- **Web Manifest:** `name: 'Sokoban'`, `display: 'standalone'`, `start_url: '/sokoban/'`, theme color `#5e81ac` (Nord frost blue).
|
||||
- **Icons:** 192×192, 512×512, plus 512×512 maskable icon for adaptive display on Android.
|
||||
- **Service Worker:** Workbox auto-generated. Caches JS, CSS, HTML, PNG, SVG, WebManifest. `registerType: 'autoUpdate'` checks for updates on each visit.
|
||||
- **Offline support:** All assets cached — full 155 levels playable without network after first visit.
|
||||
|
||||
## Deployment
|
||||
Static build via `vite build --config vite/config.prod.mjs`, base `/sokoban/`, output pushed to GitHub Pages. No server-side components. Bundle size ≈ **65 kB / 23 kB gzipped** — down from ~1.5 MB in the Phaser version.
|
||||
Static build via `vite build --config vite/config.prod.mjs`, base `/sokoban/`, output pushed to GitHub Pages. No server-side components. Bundle size ≈ **65 kB / 23 kB gzipped** (PWA metadata adds ~2 kB, still well under budget).
|
||||
Reference in new issue
Block a user