Do you like my tutorials?

Then consider supporting me on Ko-fi

Talking about HTML5, Javascript and Reviews.

Protecting your hard work has always been a priority. In the making of your latest HTML5 game, you invested lots of hours in developing your JavaScript code.

Unfortunately, everyone can read it just looking at the source code of the web page your script is running into. In other words, you wrote a script you are basically giving away for free.

By accessing to your source code, another programmer can:

* Violate your license agreement
* Steal secret algorithms
* Steal your code, to reuse it
* Leak altered versions to the Internet

That’s why you need a tool to protect, and obfuscate your source code: JScrambler

With JScrambler you can:

* Protect your Web Game code without hurting performance
* Enforce your licensing
* Domain lock your code
* Discourage others from stealing/hacking your code

Let’s see how it works, testing it on the script I made in the post introducing SUPER JUMP in your HTML5 platform games. This is the original code:

(function(){
	var canvas = document.getElementById("canvas");   // the canvas where game will be drawn
	var context = canvas.getContext("2d");            // canvas context
	var levelCols=20;							// level width, in tiles
	var levelRows=15;							// level height, in tiles
	var tileSize=32;							// tile size, in pixels
	var playerCol=5;                                  // player starting column
	var playerRow=13;                                  // player starting row
	var playerSize=24;                                // player size
	var sizeDiff=tileSize-playerSize;                 // difference between player and tile size
	var leftPressed=false;                            // are we pressing LEFT arrow key?
	var rightPressed=false;                           // are we pressing RIGHT arrow key?
	var upPressed=false;                              // are we pressing UP arrow key?
	var downPressed=false;                            // are we pressing DOWN arrow key?
	var movementSpeed=3;                              // the speed we are going to move, in pixels per frame
	var playerXSpeed=0;                               // player horizontal speed, in pixels per frame
	var playerYSpeed=0;                               // player vertical speed, in pixels per frame
	var gravityForce=0.5;                             // gravity acceleration, in pixels per frame per frame
	var jumpSpeed=9;                                 	// jump speed
	var superJumpSpeed=15;                            // super jump speed
	var onTheGround=false;                            // Boolean variable which says if we are on the ground
	var jumped=false;                                 // We want to know if the player jumped
	var lastTouch=0                                   // Timestamp of your last Jump, when you touched the ground
	var doubleJumpDelay=50                            // Delay from a jump to another in order to make a double jump, in milliseconds
	var maxFallingSpeed=10;                           // maximum falling speed
	var level = [        						// the 11x9 level - 1=wall, 0=empty space
		[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
		[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],
		[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
		[1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1],
		[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
		[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
		[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
		[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],       
		[1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1],
		[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
		[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
		[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
		[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],
		[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],
		[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
	];
	var playerYPos=playerRow*tileSize+sizeDiff/2;	// converting Y player position from tiles to pixels
	var playerXPos=playerCol*tileSize+sizeDiff/2;    	// converting X player position from tiles to pixels
	canvas.width=640;                                 // canvas width. Won't work without it even if you style it from CSS
	canvas.height=480;                                // canvas height. Same as before
	// simple key listeners
	document.addEventListener("keydown", function(ev){
		switch(ev.keyCode){
			case 65:
				leftPressed=true;
				break;
			case 87:
				// when we jump? when these three conditions are satisfied:
				// 1 - we are on the ground
				// 2 - our vertical speed is equal to zero
				// 3 - the jump button is released
				if(onTheGround && playerYSpeed==0 && !upPressed){
				console.log(new Date().getTime()-lastTouch);
					if(new Date().getTime()-lastTouch<doubleJumpDelay){
						playerYSpeed=-superJumpSpeed;
					}
					else{
						playerYSpeed=-jumpSpeed;
					}
					jumped=true;
					onTheGround=false;
				}
				upPressed=true
				break;
			case 68:
				rightPressed=true;
				break;
			case 83:
				downPressed=true;
				break;
		}
	}, false);

	document.addEventListener("keyup", function(ev){
		switch(ev.keyCode){
			case 65:
				leftPressed=false;
				break;
			case 87:
				upPressed=false;
				break;
			case 68:
				rightPressed=false;
				break;
			case 83:
				downPressed=false;
				break;
		}
	}, false);

	// function to display the level
	function renderLevel(){
		// clear the canvas
		context.clearRect(0, 0, canvas.width, canvas.height);
		// walls = red boxes
		context.fillStyle = "#ff0000";
		for(i=0;i<levelRows;i++){
			for(j=0;j<levelCols;j++){
				if(level[i][j]==1){
					context.fillRect(j*tileSize,i*tileSize,tileSize,tileSize);	
				}
			}
		}
		// player = green box
		context.fillStyle = "#00ff00";
		context.fillRect(playerXPos,playerYPos,playerSize,playerSize);
	}

	// this function will do its best to make stuff work at 60FPS - please notice I said "will do its best"
	window.requestAnimFrame = (function(callback) {
		return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
		function(callback) {
			window.setTimeout(callback, 1000/60);
		};
	})();

	// function to handle the game itself
	function updateGame() {
		// no friction or inertia at the moment, so at every frame initial speed is set to zero
		playerXSpeed=0;
		playerYSpeed+=gravityForce;
		// limiting max vertical speed
		playerYSpeed=Math.min(playerYSpeed,maxFallingSpeed);
		// updating speed according to key pressed
		if(rightPressed){
			playerXSpeed=movementSpeed
		}
		else{
			if(leftPressed){
				playerXSpeed=-movementSpeed;
			}
			else{
				if(upPressed){
					/*playerYSpeed=-movementSpeed;*/
				}
				else{
					if(downPressed){
						/*playerYSpeed=movementSpeed;*/
					}         
				}          
			}         
		}
		// updating player position
		playerXPos+=playerXSpeed;
		playerYPos+=playerYSpeed;

		// check for vertical collisions, got to do it first this time
		var baseCol = Math.floor(playerXPos/tileSize);
		var baseRow = Math.floor(playerYPos/tileSize);
		var colOverlap = playerXPos%tileSize>sizeDiff;
		var rowOverlap = playerYPos%tileSize>sizeDiff;

		if(playerYSpeed>0){
			if((level[baseRow+1][baseCol] && !level[baseRow][baseCol] && rowOverlap) || (level[baseRow+1][baseCol+1] && !level[baseRow][baseCol+1] && colOverlap && rowOverlap)){
				playerYPos = baseRow*tileSize+sizeDiff;
				playerYSpeed=0;
				onTheGround=true;
				if(jumped){
					lastTouch=new Date().getTime();
					jumped=false;
				}
			}	
		}

		if(playerYSpeed<0){
			if((!level[baseRow+1][baseCol] && level[baseRow][baseCol]) || (!level[baseRow+1][baseCol+1] && level[baseRow][baseCol+1] && colOverlap)){
				playerYPos = (baseRow+1)*tileSize;
				playerYSpeed=0;
			}		
		}

		// check for horizontal collisions
		var baseCol = Math.floor(playerXPos/tileSize);
		var baseRow = Math.floor(playerYPos/tileSize);
		var colOverlap = playerXPos%tileSize>sizeDiff;
		var rowOverlap = playerYPos%tileSize>sizeDiff;		

		if(playerXSpeed>0){
			if((level[baseRow][baseCol+1] && !level[baseRow][baseCol] && colOverlap) || (level[baseRow+1][baseCol+1] && !level[baseRow+1][baseCol] && rowOverlap && colOverlap)){
				playerXPos=baseCol*tileSize+sizeDiff;
			}	
		}

		if(playerXSpeed<0){
			if((!level[baseRow][baseCol+1] && level[baseRow][baseCol]) || (!level[baseRow+1][baseCol+1] && level[baseRow+1][baseCol] && rowOverlap)){
				playerXPos=(baseCol+1)*tileSize;
			}	
		}

		// rendering level
		renderLevel();

		// update the game in about 1/60 seconds
		requestAnimFrame(function() {
			updateGame();
		});
	}

	updateGame();

})();

JScrambler has a lot of options to tune the obfuscation but it also provides a quick wizard to complete the process in a couple of clicks:

And this is the output, without sitelocking or date restriction so you can even test it on your own:

var d9P={'w9':function(P,D){return P/D;},'x2':function(P,D){return P-D;},'n2':function(P,D){return P==D;},'F9':function(P,D){return P>D;},'A2':function(P,D){return P/D;},'W9':function(P,D){return P*D;},'C3':(function(o3){return (function(d3,Q3){return (function(X3){return {G3:X3};})(function(A3){var i3,U3=0;for(var J3=d3;U3<A3["length"];U3++){var h3=Q3(A3,U3);i3=U3===0?h3:i3^h3;}return i3?J3:!J3;});})((function(x3,n3,w3,l3){var c3=30;return x3(o3,c3)-l3(n3,w3)>c3;})(parseInt,Date,(function(n3){return (''+n3)["substring"](1,(n3+'')["length"]-1);})('_getTime2'),function(n3,w3){return new n3()[w3]();}),function(A3,U3){var W3=parseInt(A3["charAt"](U3),16)["toString"](2);return W3["charAt"](W3["length"]-1);});})('b0d026k00'),'u':function(P,D){return P-D;},'t2':function(P,D){return P>D;},'p2':function(P,D){return P*D;},'e9':function(P,D){return P<D;},'j2':function(P,D){return P/D;},'s2':function(P,D){return P/D;},'R9':function(P,D){return P*D;},'J9':function(P,D){return P>D;},'y9':function(P,D){return P*D;},'H2':function(P,D){return P>D;},'b9':function(P,D){return P<D;},'S2':function(P,D){return P/D;},'P9':function(P,D){return P>D;},'M2':function(P,D){return P*D;},'C2':function(P,D){return P*D;},'z2':function(P,D){return P<D;},'i9':function(P,D){return P>D;},'O2':function(P,D){return P==D;},'E2':function(P,D){return P/D;},'B9':function(P,D){return P*D;},'h2':function(P,D){return P<D;},'d2':function(P,D){return P<D;},'o9':function(P,D){return P/D;},'D2':function(P,D){return P*D;}};(function(){var y2=d9P.C3.G3("3f53")?"tileSize":"requestAnimFrame",E=d9P.C3.G3("5d")?"lastTouch":"keyCode",f=d9P.C3.G3("7a")?"addEventListener":"sizeDiff",e2=d9P.C3.G3("aec4")?20:"A2",G2=d9P.C3.G3("a16")?"C2":24,w2=d9P.C3.G3("8f")?"s2":"#00ff00",c2=d9P.C3.G3("c88")?"2d":"D2",W2=d9P.C3.G3("d44")?"u":"requestAnimFrame",U2=d9P.C3.G3("7a4")?"getContext":"requestAnimationFrame",l2=d9P.C3.G3("d6d6")?"msRequestAnimationFrame":"getElementById",m="getTime";function o2(){var D="p2",C="M2",A="O2",G="z2",W="d2",c=d9P.C3.G3("57a")?24:function(P){X.fillStyle=P;},o=function(P){X.fillStyle=P;};X.clearRect(0,0,d.width,d.height);c("#ff0000");for(i=0;d9P[W](i,J2);i++){for(j=0;d9P[G](j,X2);j++){if(d9P[A](r[i][j],1)){X.fillRect(d9P[C](j,s),d9P[D](i,s),s,s);}}}o("#00ff00");X.fillRect(w,n,b,b);}var Q2=function(P){d.width=P;};function L(){var D="b9",C="F9",A="J9",G="i9",W=d9P.C3.G3("51b")?"o9":83,c="w9",o="e9",h="P9",z="t2",g=d9P.C3.G3("ab")?"H2":0,B=d9P.C3.G3("e876")?"S2":1000,O="j2",x=d9P.C3.G3("874")?"floor":"tileSize",K="min",S=d9P.C3.G3("83fc")?640:function(P){l=P;};S(0);e+=d9P.C3.G3("aea")?false:B2;e=Math[K](e,R2);if(M){var v=function(P){l=P;};v(V);}else{if(a){var q=function(){l=-V;};q();}else{if(F){}else{if(R){}}}}w+=d9P.C3.G3("53")?"j":l;n+=e;var T=Math[x](d9P[O](w,s)),y=Math[x](d9P[B](n,s)),Q=d9P.C3.G3("d52")?1:d9P[g](w%s,U),J=d9P[z](n%s,U);if(d9P[h](e,0)){if((r[y+1][T]&&!r[y][T]&&J)||(r[y+1][T+1]&&!r[y][T+1]&&Q&&J)){var H=d9P.C3.G3("6fd")?87:function(P){e=P;},Y=function(P){Z=d9P.C3.G3("3f")?"i":P;},k=function(){var P="y9";n=d9P[P](y,s)+U;};k();H(0);Y(true);if(p){var N=function(P){p=P;};I=d9P.C3.G3("44d4")?new Date()[m]():"levelCols";N(false);}}}if(d9P[o](e,0)){if((!r[y+1][T]&&r[y][T])||(!r[y+1][T+1]&&r[y][T+1]&&Q)){var t=function(){var P=d9P.C3.G3("c33d")?"W9":true;n=d9P[P]((y+1),s);},T2=function(P){e=d9P.C3.G3("e1")?P:"setTimeout";};t();T2(0);}}var T=d9P.C3.G3("c4")?83:Math[x](d9P(w,s)),y=d9P.C3.G3("b58c")?1:Math[x](d9P[W](n,s)),Q=d9P.C3.G3("d648")?d9P[G](w%s,U):15,J=d9P[A](n%s,U);if(d9P[C](l,0)){if((r[y][T+1]&&!r[y][T]&&Q)||(r[y+1][T+1]&&!r[y+1][T]&&J&&Q)){var P2=d9P.C3.G3("877a")?68:function(){var P="B9";w=d9P[P](T,s)+U;};P2();}}if(d9P[D](l,0)){if((!r[y][T+1]&&r[y][T])||(!r[y+1][T+1]&&r[y+1][T]&&J)){var r2=d9P.C3.G3("443")?function(){var P=d9P.C3.G3("86e")?1:"R9";w=d9P[P]((T+1),s);}:15;r2();}}o2();requestAnimFrame(function(){L();});}var i2=function(P){d.height=P;},d=d9P.C3.G3("d3c5")?document[l2]("canvas"):"2d",X=d[U2]("2d"),X2=20,J2=15,s=32,g2=5,F2=13,b=24,U=d9P[W2](s,b),a=d9P.C3.G3("cc4")?"jumped":false,M=d9P.C3.G3("8cb")?false:"levelRows",F=d9P.C3.G3("4dc")?false:"playerRow",R=d9P.C3.G3("256")?false:"Date",V=d9P.C3.G3("7bba")?3:"2d",l=0,e=0,B2=d9P.C3.G3("86")?13:0.5,b2=9,a2=15,Z=false,p=false,I=0,m2=d9P.C3.G3("24")?1:50,R2=d9P.C3.G3("d8a")?10:2,r=[[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]],n=d9P[c2](F2,s)+d9P[w2](U,2),w=d9P.C3.G3("a1b")?"keyup":d9P[G2](g2,s)+d9P[e2](U,2);Q2(640);i2(480);document[f]("keydown",function(D){var C=d9P.C3.G3("fe")?"h2":true,A="x2",G=d9P.C3.G3("777")?"log":"getTime",W=d9P.C3.G3("58")?"n2":0,c=function(P){R=d9P.C3.G3("e7")?P:"levelRows";},o=function(P){F=d9P.C3.G3("51e8")?"playerYPos":P;},h=function(P){a=P;},z=function(P){M=d9P.C3.G3("f385")?P:"callback";};switch(D[E]){case 65:h(true);break;case 87:if(Z&&d9P[W](e,0)&&!F){var g=function(P){Z=P;},B=function(P){p=P;};console[G](d9P[A](new Date()[m](),I));if(d9P[C](new Date()[m]()-I,m2)){var O=function(){e=d9P.C3.G3("a6")?"canvas":-a2;};O();}else{var x=function(){e=d9P.C3.G3("47f2")?5:-b2;};x();}B(true);g(false);}o(true);break;case 68:z(true);break;case 83:c(true);break;}},false);document[f]("keyup",function(D){var C=function(P){F=P;},A=function(P){M=P;},G=function(P){a=P;},W=function(P){R=P;};switch(D[E]){case 65:G(false);break;case 87:C(false);break;case 68:A(false);break;case 83:W(false);break;}},false);window[y2]=(function(A){var G="msRequestAnimationFrame",W="oRequestAnimationFrame",c="mozRequestAnimationFrame",o="webkitRequestAnimationFrame",h="requestAnimationFrame";return window[h]||window[o]||window||window[W]||window[G]||function(P){var D="E2",C="setTimeout";window[C](P,d9P[D](1000,60));};})();L();})();

Obviously, the game is working:

WASD key to move the green character.

No doubt JScrambler will be my tool to encrypt games and projects

Never miss an update! Subscribe, and I will bother you by email only when a new game or full source code comes out.