mirror of
https://github.com/tiennm99/sokoban.git
synced 2026-05-23 00:25:54 +00:00
8a3d4b4a9d
Replace Phaser 3 with Svelte 5 as the rendering and UI layer. The framework-agnostic core (level parser, board model, progress store, microban level data) moves from src/game/core → src/lib/core with zero code changes. Scenes and the hand-rolled button factory are gone; in their place: - src/App.svelte root router (menu / levels / game) - src/views/MenuView title + play + progress + hints - src/views/LevelSelectView paginated 5x4 grid with native <button>s - src/views/GameView owns BoardModel, handles input, HUD, win - src/views/Board purely presentational DOM renderer - src/views/AppButton shared themed wrapper for native <button> - src/app.css Nord palette ported to CSS variables GameView uses a non-reactive BoardModel ref and syncs plain snapshot fields (player, boxes, moves, won) into $state after every mutation — Board consumes only plain props, so Svelte reactivity stays predictable and the core class stays framework-agnostic. GameView is keyed on levelIndex in App, so changing level remounts with fresh state. Native <button> everywhere kills the click-hitbox class of bugs. Animations are now CSS transform transitions (110ms) instead of tweens. Bundle shrinks from ~1.5 MB Phaser to ~65 kB JS / 23 kB gzipped — about 60x smaller. Removed: phaser, terser, src/game, log.js (analytics ping), phasermsg vite plugin, manual Phaser chunks, terser config, public/style.css. Scripts simplified to dev/build. Docs updated: codebase summary, architecture, code standards, changelog, roadmap, README.
2.1 KiB
2.1 KiB
Code Standards
Language & Toolchain
- ES modules, modern JS (no TypeScript).
- Svelte 5 with runes (
$state,$derived,$props). - Vite as build tool. Dev:
npm run dev. Prod:npm run build.
Naming
- Plain JS files: kebab-case with descriptive names (
board-model.js,progress-store.js). - Svelte components: PascalCase.svelte per ecosystem convention (
MenuView.svelte,AppButton.svelte). - Classes: PascalCase (
BoardModel). - Functions and variables: camelCase.
- Constants: UPPER_SNAKE for module-level tuning knobs (
REPEAT_MS,PER_PAGE).
File size
- Code files must stay under 200 lines of code.
- Pure-data files (levels, palettes) are exempt.
Architecture rules
- Views (
src/views/*.svelte) own layout + user interaction. Each screen is one component, kept under 200 LOC. - Core (
src/lib/core/) is pure JS — no Svelte imports. Anything that can be unit-tested without a DOM lives here (parser, board model, progress store). - Data (
src/lib/data/) is framework-agnostic static data. Board.svelteis purely presentational: plain props in, DOM out. It does not import or touchBoardModel.GameView.svelteowns the mutableBoardModelinstance and callssyncFromModel()after every mutation to reassign the reactive$statesnapshots thatBoardconsumes.- No new dependencies without updating this doc.
Style
- Prefer composition over inheritance.
- Fail loudly during development (console.error on unexpected state), fail gracefully at runtime (try/catch around level parsing, progress store).
- Comments: short, explain why, not what. File headers give a one-sentence purpose.
Git / commits
- Conventional commits (
feat:,fix:,refactor:,docs:,chore:). - Never commit dotenv, keys, or build artifacts.
- Run
npm run build-nologbefore pushing to catch compile errors.
Testing strategy (current)
No automated tests yet. Manual smoke test: load menu → play level 1 → complete → verify progress saved in localStorage → reload page → verify completion persists.
Future: unit tests for level-parser.js and board-model.js (both framework-free JS).