Skip to content

Instantly share code, notes, and snippets.

@friday
Last active January 1, 2016 02:39
Show Gist options
  • Select an option

  • Save friday/8081042 to your computer and use it in GitHub Desktop.

Select an option

Save friday/8081042 to your computer and use it in GitHub Desktop.
A Pen by Albin Larsson.
<!DOCTYPE html>
<html>
<head>
<title>NES gamepad in CSS3</title>
<link rel="stylesheet" src="nespad.js"></style>
</head>
<body>
<div id="nespad">
<div class="cord"></div>
<fieldset class="dpad-pane">
<div class="dpad-hole"></div>
<div id="dpad">
<canvas height="400" id="dpad-body" width="400"></canvas><button class="button" id="up"></button><button class="button" id="right"></button><button class="button" id="down"></button><button class="button" id="left"></button>
</div>
</fieldset>
<fieldset class="menu-pane">
<div class="labels">
<label class="select" for="select">Select</label><label class="start" for="start">Start</label>
</div>
<div class="buttons">
<button class="button select" id="select">Select</button><button class="button start" id="start">Start</button>
</div>
</fieldset>
<fieldset class="action-pane">
<div class="logo">Nintendo</div>
<div class="buttons">
<label class="label">B<button class="button" id="b"></button></label><label class="label">A<button class="button" id="a"></button></label>
</div>
</fieldset>
</div>
<style src="nespad.js"></style>
</body>
</html>

NES-gamepad

NES-gamepad built with css3. No images. No javascript apart from the d-pad (which is a canvas). Test it here. Try pressing the buttons.

Supported in modern webkit or gecko-based browsers and IE9+

License.

/**
* Add handlers to dpad-buttons
*/
(function () {
"use strict";
var pad = document.getElementById("dpad"),
i = 0,
padbuttons = pad.getElementsByClassName("button"),
click = function(){
pad.className = this.id;
document.onmouseup = function(){
pad.className = "";
};
};
for (i = 0; i < padbuttons.length; i+=1) {
padbuttons[i].onmousedown = click;
}
}());
/**
* Draw d-pad
*/
(function () {
"use strict";
var canvas = document.getElementById("dpad-body");
function angularShape(canvas, coords) {
var shape = canvas.getContext("2d"),
i = 0;
shape.beginPath();
shape.moveTo(coords[0][0], coords[0][1]);
coords.slice(1);
for (i = 0; i < coords.length; i+=1) {
shape.lineTo(coords[i][0], coords[i][1]);
}
shape.closePath();
return shape;
}
function linearFill(shape, color1, color2, coords) {
var bg = shape.createLinearGradient(coords[0], coords[1], coords[2], coords[3]);
bg.addColorStop(0, color1);
bg.addColorStop(1, color2);
shape.fillStyle = bg;
shape.fill();
}
function ySide(canvas, y, xFrom, xTo) {
var shape = angularShape(canvas, [
[y, xFrom],
[y + 5, xFrom + 3.5],
[y + 5, xTo + 3.5],
[y, xTo]
]);
linearFill(shape, "#666", "#000", [y, xFrom, y + 15, xFrom]);
}
function xSide(canvas, x, yFrom, yTo) {
var shape = angularShape(canvas, [
[yFrom, x],
[yFrom + 5, x + 3.5],
[yTo + 5, x + 3.5],
[yTo, x]
]);
linearFill(shape, "#666", "#000", [yFrom, x, yFrom, x + 15]);
}
// draw the sides first
xSide(canvas, 63.5, 0, 100);
xSide(canvas, 100, 36.5, 63.5);
ySide(canvas, 63.5, 0, 36.5);
ySide(canvas, 63.5, 63.5, 100);
ySide(canvas, 100, 36.5, 63.5);
// draw the d-pad
var plus = angularShape(canvas, [
[0, 36.5],
[36.5, 36.5],
[36.5, 0],
[63.5, 0],
[63.5, 36.5],
[100, 36.5],
[100, 63.5],
[63.5, 63.5],
[63.5, 100],
[36.5, 100],
[36.5, 63],
[0, 63.5]
]);
plus.fillStyle = "#1a1a1a";
plus.shadowColor = "rgba(0, 0, 0, 0.6)";
plus.shadowBlur = 15;
plus.shadowOffsetX = 20;
plus.shadowOffsetY = 10;
plus.fill();
}());
/**
* Font-definition & partial css reset. Only Woff, since we lack support for IE8 anyway.
*/
@font-face {
font-family: 'Pretendo';
src: url('http://attackmupp.com/resources/nespad/Pretendo.woff') format('woff');
}
@font-face {
font-family: 'NESController';
src: url('http://attackmupp.com/resources/nespad/nes_controller_cad_mrshrike.woff') format('woff');
}
* {
box-sizing: border-box;
font: inherit;
}
body { font: 15px/2 nescontroller,sans-serif; }
.button {
outline: none;
transition: all .05s ease;
}
/**
* NES-gamepad
*/
#nespad {
margin: 20px auto;
border: 1em solid #e2dedb;
border-top-width: 3em;
border-radius: .3em;
background-color: #2a2a2a;
width: 40em;
height: 17.5em;
color: #c3442d;
font: 15px/2 nescontroller,sans-serif;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
box-shadow:
.1em .1em 0 hsla(0, 0%, 100%, .5), /* border */
.075em .1em 0 hsla(0, 0%, 80%, 1), /* 3d */
.15em .2em 0 hsla(0, 0%, 78%, 1),
.225em .3em 0 hsla(0, 0%, 76%, 1),
.3em .4em 0 hsla(0, 0%, 74%, 1),
.375em .5em 0 .1em hsla(0, 0%, 72%, 1),
.425em .6em 0 .1em hsla(0, 0%, 70%, 1),
.5em .7em 0 .1em hsla(0, 0%, 68%, 1),
.575em .8em 0 .1em hsla(0, 0%, 66%, 1),
.65em .9em 0 .1em hsla(0, 0%, 64%, 1),
.725em 1em 0 .1em hsla(0, 0%, 62%, 1),
.775em 1.1em 0 .08em hsla(0, 0%, 40%, 1), /* back piece */
.800em 1.1em 0 .13em hsla(0, 0%, 60%, 1),
.875em 1.2em 0 .13em hsla(0, 0%, 58%, 1),
.950em 1.3em 0 .13em hsla(0, 0%, 56%, 1),
1.025em 1.4em 0 .13em hsla(0, 0%, 54%, 1),
1.1em 1.5em 0 .13em hsla(0, 0%, 52%, 1),
1.175em 1.6em 0 .13em hsla(0, 0%, 50%, 1),
0.4em 1.1em .5em hsla(0, 0%, 20%, .1), /* shadow */
0.8em 1.3em .6em hsla(0, 0%, 20%, .1),
1.2em 1.6em .7em hsla(0, 0%, 20%, .1),
1.6em 1.8em .8em hsla(0, 0%, 20%, .1),
2em 2em .9em hsla(0, 0%, 20%, .1),
2.4em 2.2em 1em hsla(0, 0%, 20%, .1),
2.8em 2.4em 1.1em hsla(0, 0%, 20%, .1),
3.2em 2.6em 1.2em hsla(0, 0%, 20%, .1),
3.6em 2.8em 1.3em hsla(0, 0%, 20%, .1),
4em 3em 1.4em hsla(0, 0%, 20%, .1); }
.cord {
position: absolute;
top: -1em;
width: 1.1em;
height: 3em;
background-color: #bbb;
margin-left: 10em;
box-shadow: -.2em 0 .2em .49em #222 inset;
}
.cord:before { /* cord dent */
content: '';
position: absolute;
width: 1.7em;
height: .7em;
top: 2.35em;
left: -.4em;
background-color: #e2dedb;
box-shadow: -.05em -.1em .3em .1em #ccc inset;
}
.dpad-pane {
display: inline-block;
vertical-align: top;
margin: 6.5em 4.5em 5em;
width: 2.6em;
height: 2.6em;
position: relative;
}
.dpad-pane:before, .dpad-pane:after {
content: "";
background-color: #ddd;
width: 100%;
height: 280%;
position: absolute;
top: -94%;
left: 0;
border-radius: .3em;
}
.dpad-hole:before, .dpad-hole:after {
content: "";
background-color: #000;
margin: 7%;
width: 86%;
height: 265%;
position: absolute;
top: -93%;
left: 0;
border-radius: .2em;
z-index: 1;
}
.dpad-pane:after, .dpad-hole:after {
transform: rotate(90deg);
}
#dpad {
position: relative;
z-index: 1;
top: -.006em;
left: -.1em;
}
#dpad:after { /* dpad-pit */
content: "";
position: absolute;
z-index: 1;
width: 1.2em;
height: 1.2em;
margin: .4em .5em;
border-radius: 1em;
background: -webkit-radial-gradient(76% 63%, circle closest-corner, hsla(0, 0%, 60%, 0.45), hsla(0, 0%, 10%, 1) 100%);
background: -moz-radial-gradient(76% 63%, circle closest-corner, hsla(0, 0%, 60%, 0.45), hsla(0, 0%, 10%, 1) 100%);
background: radial-gradient(76% 63%, circle closest-corner, hsla(0, 0%, 60%, 0.45), hsla(0, 0%, 10%, 1) 100%);
box-shadow: -3px -2px 4px -1px #444444 inset /* scalable units did not work well across browsers */;
}
#dpad.up {
transform: rotate(.4deg) scaleY(0.98);
margin-top: .05em;
margin-left: .15em;
}
#dpad.right {
transform: rotate(.5deg) scaleX(1.02);
margin-top: .01em;
margin-left: .11em;
}
#dpad.down {
transform: rotate(-.6deg) scaleY(1.01);
margin-top: .05em;
margin-left: .05em;
}
#dpad.left {
transform: rotate(-.8deg) scaleX(0.97);
margin-top: .015em;
margin-left: .1em;
}
#dpad-body {
left: -2.3em;
top: -2.3em;
position: absolute;
z-index: 1;
}
#dpad .button {
position: absolute;
z-index: 2;
width: 2em;
height: 2em;
background-color: rgba(0, 0, 0, 0); /* "transparent" buttons in ie9 aren't clickable, but rgba can be used */
border: none;
padding: 0;
}
#dpad .button:before {
content: "";
display: block;
position: absolute;
margin: 0 .55em 0;
width: .8em;
height: .8em;
border-width: .1em;
border-style: solid;
transform: rotate(315deg);
}
#dpad .button:after {
content: "";
display: block;
position: absolute;
margin: .5em .5em 0;
width: .8em;
height: .45em;
border-width: .1em;
border-style: solid;
}
#up { top: -2.7em; }
#up:before { border-color: #151515 #444 transparent transparent; }
#up:after { border-color: transparent #444 #444 #151515; }
#right {
left: 2.7em;
transform: rotate(90deg);
}
#right:before { border-color: #444 #444 transparent transparent; }
#right:after { border-color: transparent #444 #151515 #151515; }
#down {
top: 2.7em;
transform: rotate(180deg);
}
#down:before { border-color: #444 #151515 transparent transparent; }
#down:after { border-color: transparent #151515 #151515 #444; }
#left {
left: -2.7em;
transform: rotate(270deg);
}
#left:before { border-color: #444 #151515 transparent transparent; }
#left:after { border-color: transparent #151515 #444 #444; }
.menu-pane {
display: inline-block;
vertical-align: top;
width: 11.5em;
height: 100%;
overflow: hidden;
overflow: -moz-hidden-unscrollable; /* normal hidden doesn't work in firefox here */
border: 0 solid rgba(100, 100, 100, .8);
border-width: .1em 0; }
.menu-pane .labels {
border-radius: .3em;
height: 2em;
background-color: #888;
text-transform: uppercase;
padding: 0 .8em;
margin-top: 5.2em;
box-shadow: 0 -2.7em #888, 0 -5.4em #888, 0 7em #888; }
.menu-pane label {
line-height: 1.4;
font-size: 1.3em;
}
.menu-pane .buttons {
margin: 0.67em 0;
width: 100%;
height: 3.6em;
border-radius: .3em;
background-color: #ddd;
text-transform: uppercase;
padding: 1.3em;
word-spacing: 2em;
position:relative;
}
.menu-pane .buttons:before { /* indentation */
content: "";
position: absolute;
top: .4em;
right: .4em;
bottom: .4em;
left: .4em;
border: .3em solid transparent;
border-color: #b1b1b1 #f6f6f6 #eee #bbb;
box-shadow: 1em .8em .8em -1em hsla(0, 0%, 0%, 0.3) inset; }
.menu-pane .button {
position: relative;
overflow: hidden;
top: -.3em;
left: -.16em;
height: 1.2em;
width: 3.3em;
border: 0;
border-radius: 1em;
background-color: #2a2a2a;
color: #2a2a2a;
box-shadow:
.04em .08em 0 hsla(0, 0%, 26%, 1), /* 3d */
.08em .15em 0 hsla(0, 0%, 23%, 1),
.12em .23em 0 hsla(0, 0%, 20%, 1),
.16em .3em 0 hsla(0, 0%, 17%, 1),
.16em .3em 0 .15em hsla(0, 0%, 0%, .9), /* hole */
.1em .075em .5em rgba(0, 0, 0, .3), /* shadow */
.3em .15em .5em rgba(0, 0, 0, .3),
.6em .2em .5em rgba(0, 0, 0, .3),
1.2em .4em .5em rgba(0, 0, 0, .3);
}
.menu-pane .button:active {
top: 0;
left: 0;
box-shadow:
0 0 0 .15em hsla(0, 0%, 0%, .9), /* hole */
.1em .075em .5em rgba(0,0,0,.3);
}
.start { float: right; }
.select { float: left; }
.action-pane {
display: inline-block;
vertical-align: top;
border-bottom: 1px solid transparent;
margin: 2.6em 0 0 1.1em; }
.logo {
font: 1.3em/1 pretendo;
margin: 0 0 3.3rem 2rem;
cursor: default; }
.logo:after {
content: '\AE';
vertical-align: super;
font: 0.6rem sans-serif;
}
.action-pane .label {
display: inline-block;
background-color: #ddd;
border-radius: 0.4rem;
width: 4rem;
height: 4rem;
margin-left: .8rem;
text-align: right;
line-height: 6.1em;
position: relative;
font-size: 1.5rem; }
.action-pane .button {
position: absolute;
top: .02rem;
left: .22rem;
width: 3.2rem;
height: 3.2rem;
background: #E0421B; /* fallack */
background: -webkit-radial-gradient(35% 35%, circle closest-corner, #ff8957, #E0421B 100%);
background: -moz-radial-gradient(35% 35%, circle closest-corner, #ff8957, #E0421B 100%);
background: radial-gradient(35% 35%, circle closest-corner, #ff8957, #E0421B 100%);
border-radius: 2em;
border: .08em solid hsla(10, 90%, 55%, 1);
box-shadow:
2em 1em 0.2em 0 hsla(10, 90%, 45%, .5) inset, /* reflection */
.04em .1em 0 hsla(10, 90%, 30%, 1), /* 3d */
.08em .2em 0 hsla(10, 90%, 26%, 1),
.12em .3em 0 hsla(10, 90%, 23%, 1),
.1em .24em 0 .15em hsla(0, 0%, 15%, 1), /* hole */
.1em .075em .5em rgba(0, 0, 0, .3), /* shadow */
.3em .15em .5em rgba(0, 0, 0, .3),
.6em .3em .5em rgba(0, 0, 0, .3),
1.2em .6em .5em rgba(0, 0, 0, .3);
}
.action-pane .button:active {
top: .40rem;
left: .35rem;
box-shadow:
2em 1em 0.2em 0 hsla(10, 90%, 45%, .5) inset, /* reflection */
.05em .1em 0 hsla(10,90%,30%,1), /* 3d */
0 0 0 .15em hsla(0, 0%, 15%, 1), /* hole */
.1em .075em .5em rgba(0,0,0,.3); /* shadow */
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment