JS Sidescrolling Platformer

Hi, there. I’ve been trying to create a javascript game while loosely following the freeCodeCamp tutorial here: https://www.youtube.com/watch?v=w-OKdSHRlfA
I can’t figure out why my character is jerking when I press the right or left arrow key(instead of traveling smoothly). This may be a lot to ask someone to look at, but I would greatly appreciate any feedback or help.

P.S. I have all my coding in one file as of right now, but am planning to split it up later.

<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Emilys+Candy|Fredericka+the+Great&display=swap" rel="stylesheet">
<style>
canvas{
	border: 1px solid black;
	margin:10px;
}


/*
Everything Below is for the Whole Site
*/
#container{
	width:80%;
	padding:10px;
	margin:auto;
	background:#d1e0fe;
}
body{
	background:url("chocoBG.jpg");
}



/* Navigation */
#navi{
	font-size:16pt;
	padding:10px;
	width:80%;
	margin:auto;
	text-shadow: 0px 0px 10px black;
	font-family: 'Emilys Candy', cursive;
}
#navi, #navi a{
	color:white;
	font-weight:bold;
}
#navi a, .tab{
	font-size:14pt;
	padding-left:30px;
	text-decoration:none;
}

</style>
</head>
<body>
<div id="navi">Sugar World<a href="">Some Link</a>
<a href="">Some Link</a>
<a href="">Some Link</a>
<a href="">Some Link</a>
</div>

<div id="container">

<center><canvas id="screen"></canvas></center>

</div>

<script>



//polyfill
(function() {
    var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
    window.requestAnimationFrame = requestAnimationFrame;
})();



let canvas = document.getElementById("screen");
let ctx = canvas.getContext("2d");
let width = 600;
let height = 500,
keys = [];
 
canvas.width = width;
canvas.height = height;


/////////////
//Game //
/////////////
Game = function(){

	this.world = {
		gravity:0.3,
		friction: 0.9
	}
	this.player = {
    	x : width/2,
    	y : height - 156,
    	posx : 0,
    	width : 50,
    	height : 84,
    	velx: 0,
    	vely: 0.3,
    	frameSets: {
    		bounce: [0, 1, 2 ,3 , 4],
    		turnLeft: [5, 6, 7, 8, 9, 10],
    		idleLeft: [11],
    		runRight: [12, 13, 14, 15, 16, 17],
    		runLeft: [18, 19, 20, 21, 22, 23],
    		jump: [1],
    		idleRight: [11]
    		
    	} ,
    	jumping:false,
    	getBottom:   function()  { return this.y     + this.height; },
  		getLeft:     function()  { return this.x;                   },
  		getRight:    function()  { return this.x     + this.width;  },
  		getTop:      function()  { return this.y;                   },
  		setBottom:   function(y) { this.y     = y    - this.height; },
  		setLeft:     function(x) { this.x     = x;                  },
  		setRight:    function(x) { this.x     = x    - this.width;  },
 		setTop:      function(y) { this.y     = y;                  }
    }
	//source_x, source_y
	this.sFramesArr = [[0, 0],[50, 0],[100, 0],[150, 0], [200, 0], // Bounce Anim
		[0, 84],[50, 84],[100, 84],[150, 84], [200, 84],[0, 168], // Turn left Anim
		[50, 168], //Left Static
		[100, 168],[150, 168], [200, 168], [0, 252],[50, 252],[100, 252], //RunRight
		 [200, 252], [0, 336], [50, 336], [100, 336], [150, 336],  //RunLeft
		[200, 336], [0, 420] 
	]
	let frame = 0;
	let delay = 15 * (this.player.velx + 1);
	let count = 0;
	this.animate = function (fset){
				if (frame >= game.player.frameSets[fset].length){
					frame = 0;
				}
				ctx.fillStyle = "#7599df";
				ctx.fillRect(0,0,width,height);
				display.drawBg(game.player.velx, 0)
				display.drawChar(display.squishy.image, game.sFramesArr[game.player.frameSets[fset][frame]][0], game.sFramesArr[game.player.frameSets[fset][frame]][1], game.player.x, game.player.y, game.player.width, game.player.height);
				while (count > delay){
				count = 0;
				frame ++;
				};
				count++;
	}
	this.level1 = [
		"x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x",
		"x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x",
		"x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x",
		"x", "x", "x", "x", "x", "x", "x", "x", "r", "x", "x", "p", "x", "x", "x", "x", "x", "x", "a", "s", "s", "s", "d", "x",
		"x", "x", "x", "x", "x", "x", "x", "x", "g", "x", "b", "g", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x",
		"x", "a", "s", "s", "s", "s", "d", "x", "g", "x", "g", "g", "x", "x", "a", "s", "s", "d", "x", "x", "x", "x", "x", "x",
		"x", "x", "x", "x", "x", "x", "x", "x", "g", "x", "g", "g", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x", "x"
		];
	
	this.keys = function (type, keycode) {
		this.down = type == "keydown" ? true : false;
		
		
		switch(keycode){
			case 37:
			this.moveLeft();
			break;  //left
			case 38:
			this.jump();
			break;
			case 39: 
			this.moveRight();
			break; //right
	}
	
	
	
	}
	this.moveLeft = function(){
		this.player.velx += 5;
	
	}
	this.moveRight = function(){
		this.player.velx -= 5;
	}
	this.jump = function (){
		if (!this.player.jumping){
	 		this.player.vely -= 10;
	 	}
	 	this.player.jumping = true;
	 	
	 	
	}
	
	this.collider = {
		collidePlatformTop: function (tileTop, character){
			if (game.player.getBottom() > tileTop){
				game.player.setBottom(tileTop - 0.01);
      			game.player.vely = 0;
			}
		}
	}

}




/////////////
//Display //
/////////////
Display = function(){
	this.squishy = new Display.Squishy();
	this.map = new Display.Map();
	this.drawChar = function (image, source_x, source_y, destination_x, destination_y, width, height){
	ctx.drawImage(image, source_x, source_y, width, height, Math.round(destination_x), Math.round(destination_y), width, height);
}
	this.drawMap = function(map, columns) {
		
	}
	this.drawSquishy = function(image, source_x, source_y, destination_x, destination_y, width, height) {
	
    	ctx.drawImage(image, source_x, source_y, width, height, Math.round(destination_x), Math.round(destination_y), width, height);

  }
  this.drawBg = function(x, y){
  	ctx.drawImage(display.map.image, 0, 0, 420, 336, 0 + (game.player.posx/3), 0 + y, 720, 600); //Mountain
	ctx.drawImage(display.map.image, 420, 168, 252, 84,300 + game.player.posx, 160 + y, 252, 84); //Cloud
	this.drawBridge(4, 40 + game.player.posx, 410);
  
  }
  this.drawBridge = function(width, x, y){
  	ctx.drawImage(display.map.image, 672, 84, 84, 84, x, y, 84, 84);
  	for (let i = 1; i < width; i++){
  	ctx.drawImage(display.map.image, 672, 0, 84, 84, x + (84 * i), y, 84, 84);
  	}
  	ctx.drawImage(display.map.image, 672 + 84, 0, 84, 84, x + width * 84, y, 84, 84);
  }
  this.clear = function(){
  ctx.fillStyle = "#7599df";
  }
  this.gameOver = function() {
  		ctx.fillStyle = "black";
		ctx.fillRect(0, 0, width, height);
		ctx.fillStyle = "white";
		ctx.font = "75px Fredericka the Great";
		ctx.fillText("Game Over", 100, height/2);
		}
}

Display.Squishy = function(){
	this.image = new Image();
	this.height = 84;
	this.width = 50;
  	this.columns = 5;
}

Display.Map = function(columns, tile_size){
	this.image = new Image();
	this.columns = columns;
	this.tile_size = tile_size;
}


 
 
 
 /////////////
//Load Things//
/////////////

let display = new Display();
let game = new Game();

 window.addEventListener("load", () => update());
display.squishy.image.addEventListener("load", function(event) {
    update();
    window.addEventListener("keydown", keys);
    window.addEventListener("keyup",   keys);
  }, { once:true });
  
display.map.image.src = "BGsheet.png";
display.squishy.image.src = "squishy.png";

function update(){
	//Draw Box
	ctx.fillStyle = "#7599df";
	ctx.fillRect(0,0,width,height);
	display.drawBg(0, 0); //image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight
	game.animate("bounce");
	requestAnimationFrame(update);
	//Move Player Left and Right
	if (game.player.velx > 0.09){
		ctx.fillStyle = "#7599df";
		ctx.fillRect(0,0,width,height);
		display.drawBg(game.player.velx, 0)
		game.animate("runLeft");
	}
	if (game.player.velx < -0.09){
		game.animate("runRight");
		
	}
	//Jump
	if (game.player.vely < 0){ 
		game.animate("jump");
	}
	
	
	//Friction and Gravity
	game.player.y += game.player.vely;
	game.player.posx += game.player.velx;
	game.player.velx *= game.world.friction;
	game.player.vely += game.world.gravity;
	
	
	
    if (game.player.y > height){
		display.gameOver()
		game.player.vely = 0;
		game.player.y = 630;
	}
   
    
    //Collide
    if ( game.player.getBottom() > 423 && game.player.getBottom() < 630)
    	{
    	game.collider.collidePlatformTop(423, game.player);
    	game.player.vely = 0;
    	game.player.jumping = false;
    	};
    }

keys = function(event) {

    game.keys(event.type, event.keyCode);

  };

</script>
</body>
</html>

Before we begin helping you figure out the jerky movement, you first need to fix the error showing in the browser console (see below):

pen.js:159 Uncaught DOMException: Failed to execute ‘drawImage’ on ‘CanvasRenderingContext2D’: The HTMLImageElement provided is in the ‘broken’ state.

Oh. I didn’t know that would happen if I separated the file and the images. I will have to put it on Github or something… Thank you for looking at it. One sec…

Okay. First time using Github. I think I did it right? https://github.com/AlexisLeeAnn/FirstGame/tree/master/Project
Do you have acess to everything you need from there?

I put it on codepen.io now. I hope this makes it easier. Sorry about the earlier bumble.

https://codepen.io/alexis-lee-ann-stockdale/pen/qzvrop

Got the question resolved here: https://stackoverflow.com/questions/56993678/why-is-my-character-not-moving-smoothly-in-my-2d-sidescroller?noredirect=1