Here are an assortment of small snippets that I’ve built during my 2019 js13k competition entry - I hope they’re useful to other people too!

Autozoom

This block will need some tweaking to fit your particular content, but the comments should help!

//zoom the page to fit the window
onresize=e=>{
  // zoom the page to maximise your content within the window.
  // This assumes a 640x480 canvas - change the numbers to match your canvas size
  document.body.style.zoom=Math.min(window.innerWidth/640, window.innerHeight/480);
  // Add padding at the top of the page, to centre the content vertically
  document.body.style.paddingTop=((window.innerHeight/document.body.style.zoom)-480)/2;
};

onresize(); // manually call the onresize handler, to make sure it's the right
//size from the start

// Set the left and right margins, to centre the content horizontally
document.body.style.maxWidth=640;
document.body.style.margin="auto";

Tiny gamepad

There are plenty of examples of dual thumbstick on screen controls, but many of those are far bigger than we’d want to a 13k demo. Besides, for my project, I just wanted something much simpler

You’ll need a Dpad image (you can use my example one here) or you can make your own. If you make your own, you’ll need to edit the area map shapes to match your button layout - there are lots of online tools for building these - I found this one worked nicely.

Example dpad image

<!-- dpad touch controls -->
<img src="dpad.png" id=dpad usemap="#d"><br>
<!-- old school image map - 
<map name="d">
    <area shape="circle" id=touchA coords="574,85,47">
    <area shape="circle" id=touchB coords="459,138,49">
    <area shape="poly" id=touchL coords="38,198,114,122,38,48,14,86,11,161">
    <area shape="poly" id=touchD coords="114,122,188,198,153,221,75,221,38,198">
    <area shape="poly" id=touchR coords="114,122,188,48,213,86,211,163,185,198">
    <area shape="poly" id=touchU coords="38,48,114,122,188,48,152,25,75,25">
</map>
// prevent the default events bubbling through - this disables things like the
// long press menu.
cancelEvent=e=>{
  e.preventDefault();
  e.stopPropagation();
  e.cancelBubble = true;
  e.returnValue = false
};
dpad.ontouchstart = dpad.ontouchmove = dpad.ontouchend = dpad.ontouchcancel = cancelEvent;

// On Android and iOS, hook into touchstart/touchend
// use mousedown/mouseup otherwise
// this lets the player click the controls with a mouse on non-touchscreen devices
if( /Android|iPhone|iPad|iPod/i.test(navigator.userAgent) ) {
  // touch events on Android/iOS
  d = "touchstart";
  u = "touchend"
} else {
  // mouse events otherwise
  d = "mousedown";
  u = "mouseup"
};

// Set up all the event handlers on our onscreen buttons
touchL.addEventListener(d,e=>{
  cancelEvent(e);
  keyDown(37)
}, {passive:false});

touchL.addEventListener(u,e=>{
  cancelEvent(e);
  keyUp(37)
}, {passive:false});

touchR.addEventListener(d,e=>{
  cancelEvent(e);
  keyDown(39)
}, {passive:false});

touchR.addEventListener(u,e=>{
  cancelEvent(e);
  keyUp(39)
}, {passive:false});

touchU.addEventListener(d,e=>{
  cancelEvent(e);
  keyDown(38)
}, {passive:false});

touchU.addEventListener(u,e=>{
  cancelEvent(e);
  keyUp(38)
}, {passive:false});

touchD.addEventListener(d,e=>{
  cancelEvent(e);
  keyDown(40)
}, {passive:false});

touchD.addEventListener(u,e=>{
  cancelEvent(e);
  keyUp(40)
}, {passive:false});

touchA.addEventListener(d,e=>{
  cancelEvent(e);
  keyDown(32)
}, {passive:false});

touchA.addEventListener(u,e=>{
  cancelEvent(e);
  keyUp(32)
}, {passive:false});

touchB.addEventListener(d,e=>{
  cancelEvent(e);
  keyDown(18)
}, {passive:false});

touchB.addEventListener(u,e=>{
  cancelEvent(e);
  keyUp(18)
}, {passive:false});

// Fill in this function to handle the button/key presses
keyDown=keyCode=>{
  if (keyCode == 39) { // right
    //...
    return true
  };
  if (keyCode == 37) { // left
    //... 
    return true
  };
  if (keyCode==38) { // up
    //... 
    return true
  };
  if (keyCode==40) { // up
    //... 
    return true
  };
  if (keyCode == 32) { // space - A button
    //... 
    return true
  };
  if (keyCode==18) { //left alt - B button
    //... 
    return true
  };
  return false
};

keyDown=keyCode=>{
  // handle keys being released, if necessary
}

// wire the actual keyboard events into our own functions
// Keyboard events
onkeydown=e=>{
  if (keyDown(e.keyCode)) {
    e.preventDefault()
  }
};
onkeyup=e=>{
  if (keyUp(e.keyCode)) {
    e.preventDefault()
  }
};

This is set up for cursor keys for movement, Space for the A button and left-alt for the B button. See this page for other keycodes.

More to come

I’ll keep this page updated as I think of more things to add.