JSFiddle - React, Tailwind, and code Playground

CSS

body {
	margin: 0;
	background-color: #000;
}
body, div, p, a {
	-moz-user-select: none; 
	-khtml-user-select: none; 
	-webkit-user-select: none; 
	-o-user-select: none; 
	cursor: default;
}
#container {
	width: 100vh;
	height: 100vw;
	max-width: 100vw;
	max-height: 100vh;
	background-color: #000;
	perspective: 750px;
	overflow: hidden;
}
#plane {
  	width: 60%;
	height: 80%;
	transform-style: preserve-3d;
 	transform: rotateX(5deg);
	transition: left 0.2s ease-in-out, top 0.2s ease-in-out;
}
.wall {
	color: olive;
}
.floor {
	color: gray;
	transition: color 0.2s ease-in-out;
}
.player {
	color: white;
}
.element {
	transition: left 0.2s ease-in-out, top 0.2s ease-in-out;
}
.tile {
	transition: color 0.2s ease-in-out, opacity 0.2s ease-in-out;
}
.tile, .element {
	position: absolute;
	width: calc(100% / 25);
	height: calc(100% / 25);
	background-color: transparent;
	font-family: 'Droid Sans Mono', 'Lucida Console', 'Consolas', monospace;
}
.inner-text {
	margin: 0;
	padding: 0;

	left: 50%;
	top: 50%;
	transform: translate(-50%, -50%);
}
#plane-container {
	
}
.plane-container {
  	position: absolute;
	left: 0;
	top: 0;
	width: 100%;
	height: 100%;
 	transition: left 0.2s ease-in-out, top 0.2s ease-in-out;
}
.absolute-center {
	position: absolute;
	margin: auto;
	left: 0; right: 0; top: 0; bottom: 0;
}
/* latin */
@font-face {
  font-family: 'Droid Sans Mono';
  font-style: normal;
  font-weight: 400;
  src: local('Droid Sans Mono'), local('DroidSansMono'), url(http://fonts.gstatic.com/s/droidsansmono/v7/ns-m2xQYezAtqh7ai59hJYdJ2JT0J65PSe7wdxAnx_I.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
}

JavaScript

// Changing this variable makes the calculation of the player's position go slightly off.
// Set it to 25 for the floor tiles (dots) to be perfectly lined up.
// Give it a go!
var tileScale = 9;

// Game object to supposedly reduce scope chains
function Game(){
	// Game reference for when the this keyword is out of scope
	var game = this;
	// Out of bounds function
	Array.prototype.outOfBounds = function(x, y){
		return x < 0 || y < 0 || x >= this[0].length || y >= this.length;
	}
	// Variable declarations
	this.map = [];
	this.mapSize = 25;
	this.tileScale = tileScale;
	// Player circle of vision.
	this.playerVision = 8;
	this.elements = [];
	// Function that executes when the browser resizes.
	window.onresize = this.resizeViewport = function(initial){
		game.viewportWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
		game.viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
		game.windowSize = Math.min(game.viewportWidth, game.viewportHeight);
		// Droid Sans Mono has a ratio of 3:4 (width:height), conveniently.
		game.tileWidth = game.windowSize*.6 / game.tileScale;
		game.tileHeight = game.windowSize*.8 / game.tileScale;
		// The first call to this function is at a point where these functions are not defined.
		if(initial !== true){
			game.updateList(game.tiles);
			game.updateList(game.elements);
			game.updateCamera();
		}
	}
	this.resizeViewport(true);
	// Function for attaching elements to the screen
	this.createElement = function(type, parent, properties){
		var element = document.createElement(type);
		for(var i in properties)element[i] = properties[i];
		parent.appendChild(element);
		return element;
	}
	// Find pythagorean distance, with distance x and y values found
	this.pythagorean = function(dx, dy){
		return Math.sqrt(dx*dx+dy*dy);
	}
	// Change hex value to RGB (in format of e.g. FFFFFF, without #)
	this.toRGB = function(triplet){
		var color = {};
		var sequence = ["red",...