Codytris
Codytris is a polished, browser-based falling-block puzzle game created by CodyKoInABox. It combines classic seven-piece gameplay with a clean, modern, responsive interface.
The application is fully static, has no backend, and is prepared for deployment from a GitHub repository subpath.
Features
- Seven standard tetrominoes generated with a deterministic seven-bag randomizer
- SRS-style clockwise and counter-clockwise rotation with wall kicks
- Responsive movement, soft drop, hard drop, ghost piece, and hold queue
- Classic line scoring, progressive levels, and increasing gravity speed
- Ten selectable modes with separate personal bests
- A short lock delay for precise floor movement
- Pause/resume, guarded restart, game-over handling, and automatic focus-loss pause
- Persistent per-mode high scores and local lifetime statistics
- Keyboard controls plus visible touch controls and board gestures
- Persistent settings with conflict-safe keyboard remapping
- Optional ghost piece, motion effects, and mobile touch vibration
- Responsive portrait, landscape, tablet, and desktop layouts
- Accessible controls, visible focus states, high contrast, and reduced-motion support
- Pure, deterministic game rules covered by Vitest
- GitHub Pages workflow with automatic repository subpath detection
No images, fonts, audio, game engines, or other runtime assets are downloaded.
Screenshots
Screenshots are intentionally not included yet. After publishing, add desktop and mobile captures under a docs/screenshots/ directory and replace this note with Markdown images, for example:


Technology
- React 18
- TypeScript
- Vite 8
- Modern CSS
- Vitest
- ESLint
- GitHub Actions and GitHub Pages
The board uses a 200-cell CSS grid rather than Canvas. At this scale, DOM rendering remains fast while preserving sharp responsive cells, straightforward animation, semantic surrounding controls, and maintainable styling. The timing loop only commits state when gameplay changes, so it does not force a React render on every display frame.
Local development
Requirements: Node.js 20 or newer and npm.
npm install
npm run dev
Vite prints the local URL, normally http://localhost:5173.
Available scripts
| Command | Purpose |
|---|---|
npm run dev | Start the Vite development server |
npm run typecheck | Run strict TypeScript validation |
npm run lint | Lint the full codebase with zero warnings allowed |
npm test | Run the core game test suite once |
npm run test:watch | Run tests in watch mode |
npm run build | Typecheck and create the production build in dist/ |
npm run preview | Preview the production build locally |
Run the complete local quality check with:
npm run typecheck
npm run lint
npm test
npm run build
Controls
| Action | Keyboard | Touch |
|---|---|---|
| Move left / right | Left / Right arrows | Left / right buttons or horizontal swipe |
| Soft drop | Down arrow | Down button or downward swipe |
| Rotate clockwise | Up arrow | Rotate button or tap the board |
| Rotate counter-clockwise | Z | — |
| Hard drop | Space | Drop button |
| Hold | C | Hold button |
| Pause / resume | Escape | Pause button |
| Restart | Shift + R | Restart button on larger layouts |
Every keyboard control can be changed from the in-game settings panel. Conflicting assignments are swapped so no action becomes accidentally unbound. Settings persist in localStorage alongside the high score.
Restarting an active game always requires confirmation. The game also pauses automatically when its tab becomes hidden, the browser window loses focus, or settings are opened.
Game modes
| Mode | Rules |
|---|---|
| Regular | The original Codytris rules. Gravity speeds up every 10 cleared lines. |
| Zen | Gravity stays at the starting speed, even as levels and scoring progress. |
| Rush | Gravity speeds up every 5 cleared lines for a quicker difficulty curve. |
| Survival | Starts at level 5 and disables hold. |
| Fog | Hides the ghost piece and all next-piece previews. |
| Overdrive | Starts at level 3 and speeds up every 3 cleared lines. |
| Turbo | Starts at level 7 with gravity fixed at a relentless 275 ms interval. |
| Draft | Shows only one upcoming piece and disables hold. |
| Contract | Targets 1, 2, 3, then 4 lines at once; matching clears score triple. |
| Zero-G | Disables automatic gravity so every descent is player-controlled. |
Choose a mode before starting, after game over, or from the restart confirmation. Each mode keeps its own local personal best; an existing pre-mode high score is retained as the Regular record.
Local statistics
Open the statistics button in the top bar to see lifetime runs, score, lines, four-line clears, and per-mode records. These statistics are stored only in the current browser using localStorage; Codytris does not upload or share them. Clearing the site's browser data also clears the saved statistics.
Runs are counted when they start. Progress is saved in small batches while playing and flushed when a run ends, restarts, or the page closes, avoiding storage work in the animation loop.
Architecture
src/
├── components/ React board, preview, overlay, and touch controls
├── game/ Pure rules, tetromino data, randomizer, types, persistence
├── hooks/ Frame-rate-independent timing and input lifecycle
├── settings/ Keybind definitions, preference validation, and tests
├── App.tsx Application layout and UI orchestration
└── styles.css Responsive theme, feedback, and accessibility states
The engine is independent from React. User input produces pure state transitions, while a requestAnimationFrame loop accumulates elapsed milliseconds for gravity and lock timing. As a result, falling speed is based on real elapsed time rather than monitor refresh rate.
Configuration
Repository and project metadata live in one place: site.config.ts.
Before publishing, update:
repositoryNameif the GitHub repository is not namedcodytris.repositoryUrlonce the final public URL is known. This activates the repository link in the footer.githubOwnerif the repository moves to another account.
For GitHub Actions, Vite automatically reads the repository name from GITHUB_REPOSITORY and emits URLs under /<repository-name>/. Local development always uses /. You can override either environment with VITE_BASE_PATH, including the leading slash—for example, VITE_BASE_PATH=/my-project/ npm run build.
GitHub Pages deployment
The workflow at .github/workflows/deploy-pages.yml validates and deploys the project after a push to main. It runs type checking, linting, tests, and the production build before uploading dist/ to Pages. The build also includes .nojekyll.
To publish:
- Create the GitHub repository and update
site.config.tsif its name differs. - Push this project to the repository's
mainbranch. - In GitHub, open Settings → Pages.
- Under Build and deployment, select GitHub Actions as the source.
- Run Deploy to GitHub Pages from the Actions tab, or push a new commit to
main.
For a user or organization site repository named <owner>.github.io, set VITE_BASE_PATH=/ in the workflow build environment because that kind of Pages site is hosted at the domain root.
This repository only prepares the workflow; no deployment is performed during local development.
Customization
- Change public project metadata in
site.config.ts. - Adjust the Codytris color palette and interface tokens near the top of
src/styles.css. - Tune gravity in
gravityInterval()and the lock delay insrc/hooks/useGame.ts. - Keep changes to rules in
src/game/so they remain independently testable.
License
Codytris is open-source software released under the MIT License. Copyright © 2026 Maruan Biasi El Achkar.