JSFiddle - React, Tailwind, and code Playground

by UTree

HTML

<div class="table">
	<p class="message">Use keyboard arrows to control left player. <a href="http://codepen.io/allanpope/full/a01ddb29cbdecef58197c2e829993284/">Open  in fullscreen</a>.</p>
	<div class="table-inner">
		<span class="table__goal-crease circle"></span>
		<span class="table__faceoff table__faceoff--top-left circle"></span>
		<span class="table__faceoff table__faceoff--bottom-left circle"></span>
		<span class="table__blue-line"></span>
		<span class="table__center-line"></span>
		<span class="circle"></span>
		<span class="table__blue-line table__blue-line--two"></span>
		<span class="table__faceoff table__faceoff--top-right circle"></span>
		<span class="table__faceoff table__faceoff--bottom-right circle"></span>
		<span class="table__goal-crease table__goal-crease--two circle"></span>
		</div>
</div>
<canvas id="canvas" class="table table--canvas" tabindex="0"></canvas>

CSS

// Colors
@red: fade(#bb0422, 25%);
@blue: fade(#304f86, 25%);
@black: #2e2e2e;
@grey: #F1F0F4;
@grey-dark: #7A7A7A;
@ice: #FFF;

// Table
@table-width: 800px;
@table-height: 550px;
@table-border: 15px;
@table-border-2x: @table-border * 2;

@line-width: 5px;
@blue-line-pos: 37%;
@circle-center-size: 140px;
@goal-size: 190px;

@table-faceoff-size: 80px;
@table-faceoff-pos: 20%;

* {
	box-sizing: border-box;
}

body {
	background-color: @grey;
	font-family: helvetica;
}

a {
	color: @grey-dark;
	text-decoration: none;
	transition: .3s opacity ease-out;
	
	&:hover,
	&:focus {
		opacity: .6;
	}
}

.circle {
	width: @circle-center-size;
	height: @circle-center-size;
	border-radius: 100%;
	border: @line-width solid @blue;
	position: absolute;
	top: 50%;
	left: 50%;
	margin-top: -(@circle-center-size/2);
	margin-left: -(@circle-center-size/2);
}

// Table
.table {
	width: @table-width;
	height: @table-height;
	margin-top: -(@table-height / 2);			
	margin-left: -(@table-width / 2);
	position: absolute;
	top: 50%;
	left: 50%;
	border: @table-border solid @black;
	border-radius: 70px;
	background-color: @ice;
	box-shadow: inset 0 2px 5px 0 rgba(50, 50, 50, 0.25);
	
	&:before,
	&:after {
		content: '';
		position: absolute;
		background-color: @grey-dark;
		width: @table-border;
		height: @goal-size;
		top: 50%;
		left: -@table-border;
		margin-top: -(@goal-size / 2);
	}
	
	&:after {
		left: auto;
		right: -@table-border;
	}
}

.table--canvas {
	width: @table-width - @table-border-2x;
	height: @table-height - @table-border-2x;
	margin-top: -((@table-height - @table-border-2x) / 2);			
	margin-left: -((@table-width - @table-border-2x) / 2);
	background-color: transparent;
	border-radius: 55px;
	border: none;
	
	&:focus {
		outline: none;
	}
}

.table-inner {
	overflow: hidden;
	display: block;
	position: relative;
	width: 100%;
	height: 100%;
}

.table__center-line {
	width: @line-width;
	height: 100%;
	background-color: @red;
	position: absolute;
	left: 50%;
	margin-left:...

JavaScript

var board = document.getElementById("canvas"),
		boardContext = board.getContext('2d'),
		boardWidth = window.innerWidth,
		boardHeight = window.innerHeight,
		boardCenterX = boardWidth / 2,
		boardCenterY = boardHeight / 2,
		controllers = [],
		goal = document.getElementsByClassName('table__goal-crease'),
		goalHeight = goal[0].clientHeight,
		goalPosTop = (boardHeight - goalHeight) / 2,
		score = [];

// Set width & height for canvas
board.width = boardWidth;
board.height = boardHeight;

// Set focus to canvas so keyboard events work
board.focus();

// Disc
function Disc() {

		this.startingPosX = boardCenterX;
		this.startingPosY = boardCenterY;
		this.x = this.startingPosX;
		this.y = this.startingPosY;
		this.radius = 34;
		this.mass = 15;
		this.velocityX = 0;
		this.velocityY = 0;
		this.maxSpeed = 10;
		this.frictionX = 0.997;
		this.frictionY = 0.997;
		this.acceleration = 1;
		this.color = '#000000';

		this.keepControllerInBoard = function() {
			
				// Need to determine if goal scored on x axis as well
				if (this.x > (boardWidth - this.radius) || this.x < this.radius) {

					if (this.x < this.radius) {
							  this.velocityX = 2;
						} else {
								this.velocityX = -2;
						}
				}

				// Determine if disc is to far up or down
				if (this.y > (boardHeight - this.radius) || this.y < this.radius) {

						if (this.y < this.radius) {
							  this.velocityY = 2;
						} else {
								this.velocityY = -2;
						}

				}
			
				// Keep player one controller on left hand side of screen
				if (controller.x > (boardCenterX - controller.radius) && controller.x < boardCenterX) {
						controller.velocityX = -3;
				}

				// Keep player two controller on right hand side of screen
				if (controllerTwo.x > boardCenterX && controllerTwo.x < (boardCenterX + (controllerTwo.radius / 2))) {
						controllerTwo.velocityX = +3;
				} 
		},

		// Keep disc inside board
		this.keepPuckInBoard = function() {

				// Determine if disc is to far right or...