├── .gitignore ├── assets ├── sounds.mp3 ├── audio │ ├── drop.wav │ ├── hold.wav │ ├── lock.wav │ ├── move.wav │ ├── level-up.wav │ ├── rotate.wav │ ├── clear-line.wav │ └── game-over.wav ├── fonts │ ├── icons.woff │ └── icons.woff2 ├── images │ └── pattern.png ├── stylesheets │ ├── _social.scss │ ├── _animations.scss │ ├── _nav.scss │ ├── _modal.scss │ ├── _buttons.scss │ ├── styles.scss │ ├── _type.scss │ └── _game.scss └── sounds.json ├── src ├── log.js ├── sound.js ├── Message.js ├── views │ ├── PlayfieldView.js │ ├── BlockView.js │ ├── RootView.js │ ├── GameOverView.js │ ├── TetrominoView.js │ ├── SocialView.js │ ├── TetrionView.js │ ├── GameView.js │ └── HelpView.js ├── Block.js ├── Progress.js ├── Bag.js ├── Vector.js ├── Transform.js ├── Playfield.js ├── index.js ├── Reward.js ├── Tetromino.js ├── srs.js ├── Game.js └── Tetrion.js ├── .postcssrc ├── babel.config.js ├── .editorconfig ├── .travis.yml ├── Makefile ├── index.html ├── README.md └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | .cache 2 | dist 3 | node_modules 4 | -------------------------------------------------------------------------------- /assets/sounds.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/tetris/HEAD/assets/sounds.mp3 -------------------------------------------------------------------------------- /src/log.js: -------------------------------------------------------------------------------- 1 | import nanologger from 'nanologger' 2 | 3 | export default nanologger('game') 4 | -------------------------------------------------------------------------------- /assets/audio/drop.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/tetris/HEAD/assets/audio/drop.wav -------------------------------------------------------------------------------- /assets/audio/hold.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/tetris/HEAD/assets/audio/hold.wav -------------------------------------------------------------------------------- /assets/audio/lock.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/tetris/HEAD/assets/audio/lock.wav -------------------------------------------------------------------------------- /assets/audio/move.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/tetris/HEAD/assets/audio/move.wav -------------------------------------------------------------------------------- /.postcssrc: -------------------------------------------------------------------------------- 1 | { 2 | "modules": true, 3 | "plugins": { 4 | "autoprefixer": {} 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /assets/audio/level-up.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/tetris/HEAD/assets/audio/level-up.wav -------------------------------------------------------------------------------- /assets/audio/rotate.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/tetris/HEAD/assets/audio/rotate.wav -------------------------------------------------------------------------------- /assets/fonts/icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/tetris/HEAD/assets/fonts/icons.woff -------------------------------------------------------------------------------- /assets/fonts/icons.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/tetris/HEAD/assets/fonts/icons.woff2 -------------------------------------------------------------------------------- /assets/images/pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/tetris/HEAD/assets/images/pattern.png -------------------------------------------------------------------------------- /assets/audio/clear-line.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/tetris/HEAD/assets/audio/clear-line.wav -------------------------------------------------------------------------------- /assets/audio/game-over.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nullobject/tetris/HEAD/assets/audio/game-over.wav -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@babel/preset-env', '@babel/preset-react'] 3 | } 4 | -------------------------------------------------------------------------------- /assets/stylesheets/_social.scss: -------------------------------------------------------------------------------- 1 | .social { 2 | font-size: 2rem; 3 | margin-top: 4rem; 4 | 5 | a { 6 | padding: 0 0.25rem; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [Makefile] 12 | indent_style = tab 13 | -------------------------------------------------------------------------------- /src/sound.js: -------------------------------------------------------------------------------- 1 | import { Howl } from 'howler' 2 | 3 | import sounds from '../assets/sounds.mp3' 4 | import { sprite } from '../assets/sounds.json' 5 | 6 | const sound = new Howl({ src: [sounds], sprite }) 7 | 8 | export function play (id) { 9 | if (id) { 10 | sound.play(id) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | env: 5 | global: 6 | - PATH=$HOME/.local/bin:$PATH 7 | before_install: pip install --user awscli 8 | before_deploy: make build 9 | deploy: 10 | on: 11 | branch: master 12 | provider: script 13 | script: make deploy 14 | skip_cleanup: true 15 | -------------------------------------------------------------------------------- /src/Message.js: -------------------------------------------------------------------------------- 1 | let nextId = 1 2 | 3 | /** 4 | * A message represents a message to show to the player. 5 | */ 6 | export default class Message { 7 | constructor (text) { 8 | this.text = text 9 | this.id = nextId++ 10 | } 11 | 12 | toString () { return `Message (id: ${this.id}, text: ${this.text})` } 13 | } 14 | -------------------------------------------------------------------------------- /assets/stylesheets/_animations.scss: -------------------------------------------------------------------------------- 1 | @keyframes puff { 2 | 0% { transform: scale(0, 0); opacity: 0; } 3 | 50% { opacity: 1; } 4 | 100% { transform: scale(1.2, 1.2); opacity: 0; } 5 | } 6 | 7 | @keyframes zoom-in { 8 | 0% { transform: scale(0, 0); opacity: 0; } 9 | 50% { transform: scale(1, 1); } 10 | 100% { opacity: 1; } 11 | } 12 | -------------------------------------------------------------------------------- /src/views/PlayfieldView.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import BlockView from './BlockView' 4 | import styles from '../../assets/stylesheets/styles.scss' 5 | 6 | export default ({ playfield: { blocks } }) => 7 |
The goal of Tetris is to score as many points as possible by 14 | clearing horizontal lines of blocks. The player must rotate, move, and 15 | drop the falling tetriminos inside the playfield. Lines are cleared when 16 | they are filled with blocks and have no empty spaces.
17 | 18 |As lines are cleared, the level increases and tetriminos fall 19 | faster, making the game progressively more challenging. If the blocks 20 | land above the top of the playfield, then the game is over.
21 | 22 |Made with love by Josh Bassett, 2018.
57 | 58 |Special thanks to Michael Koukoullis for inspiring me to work on Tetris in the first place. This work is based on a project we started, but never finished.
59 | 60 | 63 |