├── .gitignore ├── 3d-cube.js ├── 3d-walk.js ├── README.md ├── block.wav ├── breakout.js ├── ded.wav ├── dk-bacmusic.wav ├── dk-death.wav ├── dk-hammertime.wav ├── dk-howhigh.wav ├── dk-levelend.wav ├── dk-smash3.wav ├── dk-walking.wav ├── donkey-kong.js ├── face.png ├── hit1.wav ├── hit2.wav ├── index.html ├── over.wav ├── palette.json ├── popup.html ├── renderer.js ├── three.js ├── utils.js ├── wavy.js ├── webcam.js └── win.wav /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.swp 3 | -------------------------------------------------------------------------------- /3d-cube.js: -------------------------------------------------------------------------------- 1 | var popups = [], 2 | palette, 3 | toggleRenderButton, 4 | container, 5 | renderer, 6 | cube; 7 | 8 | function loop() { 9 | var data = new Uint8Array(renderer.width/10 * renderer.height/10 * 4), 10 | x, r, g, b, s; 11 | 12 | cube.rotation.x += .02*6; 13 | cube.rotation.y += .03*6; 14 | 15 | renderer.render(); 16 | 17 | renderer.tRenderer.readRenderTargetPixels(renderer.renderTarget, 0, 0, renderer.width/10, renderer.height/10, data); 18 | 19 | popups.forEach(function (popup, y) { 20 | s = ''; 21 | y *= 2; 22 | 23 | for (x = 0; x < renderer.width/10; x ++) { 24 | r = Math.floor(data[((y*renderer.width/10)+x)*4+0] / 16); 25 | g = Math.floor(data[((y*renderer.width/10)+x)*4+1] / 16); 26 | b = Math.floor(data[((y*renderer.width/10)+x)*4+2] / 16); 27 | 28 | s += palette[r][g][b].s; 29 | } 30 | 31 | popup.document.location.hash = s; 32 | }); 33 | 34 | setTimeout(loop, 1000/10); 35 | } 36 | 37 | function addPlane(x, y, z, xd, yd, zd, color) { 38 | material = new THREE.MeshStandardMaterial({ 39 | //color: 0xffffff * Math.random(), 40 | color: color, 41 | metalness: 0, 42 | }); 43 | 44 | mesh = new THREE.Mesh(new THREE.PlaneGeometry(4, 4, 1, 1), material); 45 | 46 | mesh.position.x = x; 47 | mesh.position.y = y; 48 | mesh.position.z = z; 49 | 50 | mesh.rotation.x = degToRad(xd); 51 | mesh.rotation.y = degToRad(yd); 52 | mesh.rotation.z = degToRad(zd); 53 | 54 | cube.add(mesh); 55 | } 56 | 57 | function loadPalette() { 58 | var xhr = new XMLHttpRequest(); 59 | 60 | xhr.open('GET', 'palette.json'); 61 | xhr.addEventListener('readystatechange', function () { 62 | if (xhr.readyState == 4) { 63 | palette = JSON.parse(xhr.responseText); 64 | 65 | loop(); 66 | } 67 | }); 68 | xhr.send(); 69 | } 70 | 71 | function toggleRender() { 72 | if (container.style.display == 'none') { 73 | container.style.display = 'block'; 74 | toggleRenderButton.innerHTML = 'hide render'; 75 | } 76 | else { 77 | container.style.display = 'none'; 78 | toggleRenderButton.innerHTML = 'show render'; 79 | } 80 | } 81 | 82 | function closeWindows() { 83 | var popup; 84 | 85 | running = false; 86 | 87 | while (popups.length) { 88 | popup = popups.shift(); 89 | popup.close(); 90 | } 91 | } 92 | 93 | function setup() { 94 | var light, x, z, 95 | closeButton; 96 | 97 | toggleRenderButton = document.createElement('button'); 98 | toggleRenderButton.innerHTML = 'show render'; 99 | toggleRenderButton.addEventListener('click', toggleRender); 100 | document.body.appendChild(toggleRenderButton); 101 | 102 | closeButton = document.createElement('button'); 103 | closeButton.innerHTML = 'close'; 104 | closeButton.addEventListener('click', closeWindows); 105 | document.body.appendChild(closeButton); 106 | 107 | container = document.createElement('div'); 108 | container.id = 'container'; 109 | container.style.display = 'none'; 110 | document.body.appendChild(container); 111 | 112 | renderer = new Renderer(); 113 | renderer.setSize(200, 140); 114 | 115 | camera = renderer.camera; 116 | 117 | light = new THREE.AmbientLight(0xdddddd); 118 | renderer.scene.add(light); 119 | 120 | light = new THREE.PointLight(0xffffff, .05); 121 | light.castShadow = true; 122 | light.position.set(0, 20, 0); 123 | renderer.scene.add(light); 124 | 125 | renderer.camera.position.z = 7; 126 | 127 | cube = new THREE.Object3D(); 128 | 129 | addPlane( 0, 0, 2, 0, 0, 0, 0xFF0000); // front 130 | addPlane( 0, 0, -2, 180, 0, 0, 0x00FF00); // back 131 | addPlane( 0, 2, 0, -90, 0, 0, 0x0000FF); // top 132 | addPlane( 0, -2, 0, 90, 0, 0, 0xFFFF00); // bottom 133 | addPlane( 2, 0, 0, 0, 90, 0, 0xFF00FF); // right 134 | addPlane(-2, 0, 0, 0, -90, 0, 0x00FFFF); // left 135 | 136 | renderer.scene.add(cube); 137 | 138 | loadPalette(); 139 | 140 | popups.forEach(function (popup) { 141 | popup.history.replaceState({}, '', '/'); 142 | }); 143 | } 144 | -------------------------------------------------------------------------------- /3d-walk.js: -------------------------------------------------------------------------------- 1 | var popups = [], 2 | palette, 3 | toggleRenderButton, 4 | container, 5 | renderer, 6 | camera, 7 | player, 8 | face, 9 | keys = {}; 10 | 11 | var map = [ 12 | 'xxxxxxxxxxxxxxxx', 13 | 'xxxxxxxx x', 14 | 'x f x', 15 | 'x x', 16 | 'x xxxxxx', 17 | 'x xxxxx x', 18 | 'x x x x', 19 | 'x x x', 20 | 'x x x x', 21 | 'x xxxxx x', 22 | 'x x', 23 | 'x x', 24 | 'xxxxxxxxxxx', 25 | ]; 26 | 27 | function loop() { 28 | var data = new Uint8Array(renderer.width/10 * renderer.height/10 * 4), 29 | x, y, r, g, b, s; 30 | 31 | var movement = {x: 0, y: 0}, 32 | speed = 2; 33 | 34 | if (keys[16]) speed *= 3; 35 | 36 | if (keys[87] || keys[38]) { 37 | movement.y = -speed; 38 | } 39 | else if (keys[83] || keys[40]) { 40 | movement.y = speed; 41 | } 42 | 43 | if (keys[68] || keys[39]) { 44 | player.rotation.y -= .2; 45 | } 46 | else if (keys[65] || keys[37]) { 47 | player.rotation.y += .2; 48 | } 49 | 50 | movement = rotateCoord(movement, radToDeg(player.rotation.y)); 51 | player.position.x += movement.x; 52 | player.position.z += movement.y; 53 | 54 | face.lookAt(player.position); 55 | 56 | renderer.render(); 57 | 58 | renderer.tRenderer.readRenderTargetPixels(renderer.renderTarget, 0, 0, renderer.width/10, renderer.height/10, data); 59 | 60 | popups.forEach(function (popup, y) { 61 | s = ''; 62 | y *= 2; 63 | 64 | for (x = 0; x < renderer.width/10; x ++) { 65 | r = Math.floor(data[((y*renderer.width/10)+x)*4+0] / 16); 66 | g = Math.floor(data[((y*renderer.width/10)+x)*4+1] / 16); 67 | b = Math.floor(data[((y*renderer.width/10)+x)*4+2] / 16); 68 | 69 | s += palette[r][g][b].s; 70 | } 71 | 72 | popup.document.location.hash = s; 73 | }); 74 | 75 | setTimeout(loop, 1000/10); 76 | } 77 | 78 | function addPlane(x, y, z, xd, yd, zd, color) { 79 | material = new THREE.MeshStandardMaterial({ 80 | //color: 0xffffff * Math.random(), 81 | color: color, 82 | metalness: 0, 83 | }); 84 | 85 | mesh = new THREE.Mesh(new THREE.PlaneGeometry(10, 20, 1, 1), material); 86 | 87 | mesh.position.x = x; 88 | mesh.position.y = y; 89 | mesh.position.z = z; 90 | 91 | mesh.rotation.x = degToRad(xd); 92 | mesh.rotation.y = degToRad(yd); 93 | mesh.rotation.z = degToRad(zd); 94 | 95 | renderer.scene.add(mesh); 96 | } 97 | 98 | function loadPalette() { 99 | var xhr = new XMLHttpRequest(); 100 | 101 | xhr.open('GET', 'palette.json'); 102 | xhr.addEventListener('readystatechange', function () { 103 | if (xhr.readyState == 4) { 104 | palette = JSON.parse(xhr.responseText); 105 | 106 | loop(); 107 | } 108 | }); 109 | xhr.send(); 110 | } 111 | 112 | window.addEventListener('keydown', function (event) { 113 | console.log(event.which); 114 | keys[event.which] = true; 115 | }); 116 | 117 | window.addEventListener('keyup', function (event) { 118 | keys[event.which] = false; 119 | }); 120 | 121 | function toggleRender() { 122 | if (container.style.display == 'none') { 123 | container.style.display = 'block'; 124 | toggleRenderButton.innerHTML = 'hide render'; 125 | } 126 | else { 127 | container.style.display = 'none'; 128 | toggleRenderButton.innerHTML = 'show render'; 129 | } 130 | } 131 | 132 | function closeWindows() { 133 | var popup; 134 | 135 | running = false; 136 | 137 | while (popups.length) { 138 | popup = popups.shift(); 139 | popup.close(); 140 | } 141 | } 142 | 143 | function setup() { 144 | var light, x, z, 145 | closeButton; 146 | 147 | toggleRenderButton = document.createElement('button'); 148 | toggleRenderButton.innerHTML = 'show render'; 149 | toggleRenderButton.addEventListener('click', toggleRender); 150 | document.body.appendChild(toggleRenderButton); 151 | 152 | closeButton = document.createElement('button'); 153 | closeButton.innerHTML = 'close'; 154 | closeButton.addEventListener('click', closeWindows); 155 | document.body.appendChild(closeButton); 156 | 157 | container = document.createElement('div'); 158 | container.id = 'container'; 159 | container.style.display = 'none'; 160 | document.body.appendChild(container); 161 | 162 | renderer = new Renderer(); 163 | 164 | camera = renderer.camera; 165 | 166 | player = new THREE.Object3D(); 167 | player.position.set(85, 0, 95); 168 | player.rotation.y = degToRad(45); 169 | 170 | player.add(camera); 171 | 172 | renderer.scene.add(player); 173 | 174 | light = new THREE.AmbientLight(0xdddddd); 175 | renderer.scene.add(light); 176 | 177 | light = new THREE.PointLight(0xffffff, .05); 178 | light.castShadow = true; 179 | light.position.set(0, 20, 0); 180 | renderer.scene.add(light); 181 | var lightHelper = new THREE.PointLightHelper(light, 1); 182 | 183 | for (z = 0; z < map.length; z ++) { 184 | for (x = 0; x < map[z].length; x ++) { 185 | if (map[z][x] != 'x') { 186 | if (map[z][x] == 'f') { 187 | material = new THREE.MeshBasicMaterial({ 188 | map: THREE.ImageUtils.loadTexture('face.png'), 189 | transparent: true 190 | }); 191 | 192 | mesh = new THREE.Mesh(new THREE.PlaneGeometry(15, 15, 1, 1), material); 193 | mesh.position.x = x * 10; 194 | mesh.position.z = z * 10; 195 | face = mesh; 196 | 197 | renderer.scene.add(mesh); 198 | } 199 | 200 | if (map[z-1][x] == 'x') { // south facing 201 | addPlane(x*10, 0, z*10-5, 0, 0, 0, 0xFF0000); 202 | } 203 | if (map[z+1][x] == 'x') { // north facing 204 | addPlane(x*10, 0, z*10+5, 180, 0, 0, 0x00FF00); 205 | } 206 | if (map[z][x+1] == 'x') { // west facing 207 | addPlane(x*10+5, 0, z*10, 0, -90, 0, 0x00FFFF); 208 | } 209 | if (map[z][x-1] == 'x') { // east facing 210 | addPlane(x*10-5, 0, z*10, 0, 90, 0, 0xFFFF00); 211 | } 212 | } 213 | } 214 | } 215 | 216 | window.addEventListener('resize', function () { 217 | renderer.resize(); 218 | }); 219 | 220 | renderer.camera.position.z = 7; 221 | 222 | loadPalette(); 223 | 224 | popups.forEach(function (popup) { 225 | popup.history.replaceState({}, '', '/'); 226 | }); 227 | } 228 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | some games and graphical things that display in the URL bars of popup windows... 2 | 3 | ## more info here: http://matthewrayfield.com/articles/games-and-graphics-in-popup-url-bars/ 4 | 5 | #### sound sources: 6 | 7 | dk-howhigh.wav, dk-death.wav, dk-walking.wav and dk-bacmusic.wav taken from http://www.classicgaming.cc/classics/donkey-kong/sounds 8 | 9 | dk-levelend.wav and dk-hammertime.wav ripped from https://www.youtube.com/watch?v=Pp2aMs38ERY 10 | 11 | dk-smash3.wav badly recreated by me :]]] 12 | -------------------------------------------------------------------------------- /block.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewRayfield/url-bar-games/a268775abec4b6a0278eae0e7b37d0b5b334858e/block.wav -------------------------------------------------------------------------------- /breakout.js: -------------------------------------------------------------------------------- 1 | var popups = [], 2 | keys = {}, 3 | 4 | map = {}, 5 | statusLine = '', 6 | 7 | levelWidth = 9, 8 | 9 | paddleSize = 3, 10 | paddleX, 11 | 12 | score = 0, 13 | lives = 2, 14 | level = 1, 15 | running = false, 16 | deathTime = 0, 17 | gameoverTime = 0, 18 | 19 | paddleSpeed = .3, 20 | ballSpeed = .03, 21 | 22 | blockLines = 2, 23 | blockCount = 0, 24 | positions, 25 | 26 | ballX, ballY, ballXV, ballYV, 27 | 28 | baseURL; 29 | 30 | var emojis = [ 31 | '🤠', '👽', '🤷', '👏', '👀', '💩', '🐸', '💯', '💊', '💸', '🔥', '🍆', '🍕', '💦', '💎', '💰', '🔫', '🚬', '🐓', '🗿' 32 | ]; 33 | 34 | function render() { 35 | popups.forEach(function (popup, y) { 36 | var s = '', x; 37 | 38 | if (!popup.document.location) return; 39 | 40 | if (y == 0) { 41 | popup.document.location.hash = statusLine; 42 | } 43 | else { 44 | for (x = 0; x < levelWidth; x ++) { 45 | if (x == Math.floor(ballX) && y == Math.floor(ballY)) { 46 | s += '🎱'; 47 | } 48 | else if (y == popups.length - 1 && x >= Math.floor(paddleX) && x < Math.floor(paddleX) + paddleSize) { 49 | if (deathTime && !(Math.floor((Date.now()-deathTime)/500) % 2)) { 50 | s += '💀'; 51 | } 52 | else { 53 | s += String.fromCharCode(0x2B1B); 54 | } 55 | } 56 | else if (map[x+','+y]) { 57 | if (gameoverTime && !(Math.floor((Date.now()-gameoverTime)/500) % 2)) { 58 | s += '💀'; 59 | } 60 | else { 61 | s += map[x+','+y]; 62 | } 63 | } 64 | else s += '⬜'; 65 | } 66 | 67 | popup.document.location.hash = '🔷' + s + '🔷'; 68 | } 69 | }); 70 | } 71 | 72 | function addBlock() { 73 | var p = positions.pop(); 74 | 75 | if (!p) { 76 | running = true; 77 | return; 78 | } 79 | 80 | map[p[0] +','+ p[1]] = emojis[Math.floor(Math.random()*emojis.length)]; 81 | blockCount ++; 82 | playSound(baseURL + 'block'); 83 | 84 | setTimeout(addBlock, 100); 85 | } 86 | 87 | function setupLevel() { 88 | var x, y; 89 | 90 | if (level == 1) { 91 | blockLines = 2; 92 | paddleSize = 3; 93 | } 94 | if (level == 2) { 95 | blockLines = 3; 96 | paddleSize = 3; 97 | } 98 | else if (level == 3) { 99 | blockLines = 3; 100 | paddleSize = 2; 101 | } 102 | else if (level == 4) { 103 | blockLines = 4; 104 | paddleSize = 2; 105 | } 106 | else if (level == 5) { 107 | blockLines = 4; 108 | paddleSize = 1; 109 | } 110 | else { 111 | blockLines = 2; 112 | paddleSize = 3; 113 | ballSpeed += .1; 114 | paddleSpeed += .1; 115 | } 116 | 117 | blockCount = 0; 118 | positions = []; 119 | 120 | for (x = 0; x < levelWidth; x ++) { 121 | for (y = 1; y <= blockLines; y ++) { 122 | positions.push([x,y]); 123 | } 124 | } 125 | 126 | positions.sort(function () {return Math.random()*2-1}); 127 | 128 | addBlock(); 129 | } 130 | 131 | function startBall() { 132 | paddleX = Math.floor((levelWidth - paddleSize)/2); 133 | 134 | ballX = paddleX; 135 | ballY = popups.length - 2; 136 | ballXV = Math.round(Math.random()) ? -.1 : .1; 137 | ballYV = -ballSpeed; 138 | } 139 | 140 | function movePaddle() { 141 | if (keys[37]) { 142 | paddleX -= paddleSpeed; // left 143 | console.log('left'); 144 | } 145 | if (keys[39]) { 146 | paddleX += paddleSpeed; // right 147 | console.log('right'); 148 | } 149 | } 150 | 151 | function addSomeRandom() { 152 | var r = (Math.random()*.15) + .05; 153 | 154 | if (ballXV > 0) ballXV = r; 155 | else ballXV = -r; 156 | } 157 | 158 | function loseLife() { 159 | lives --; 160 | 161 | if (lives < 0) { 162 | playSound(baseURL + 'over'); 163 | gameoverTime = Date.now(); 164 | } 165 | else { 166 | playSound(baseURL + 'ded'); 167 | setTimeout(function () { 168 | deathTime = 0; 169 | running = true; 170 | startBall(); 171 | }, 2000); 172 | } 173 | 174 | deathTime = Date.now(); 175 | 176 | running = false; 177 | } 178 | 179 | function moveBall() { 180 | var x, y; 181 | 182 | ballX += ballXV; 183 | ballY += ballYV; 184 | 185 | x = Math.floor(ballX); 186 | y = Math.floor(ballY); 187 | 188 | if (map[x+','+y]) { 189 | if (ballYV < 0) { 190 | ballYV = ballSpeed; 191 | } 192 | else { 193 | ballXV *= -1; 194 | } 195 | 196 | score += 1; 197 | map[x+','+y] = null; 198 | 199 | blockCount --; 200 | if (blockCount == 0) { 201 | playSound(baseURL + 'win'); 202 | running = false; 203 | level ++; 204 | setTimeout(function () { 205 | setupLevel(); 206 | startBall(); 207 | }, 1000); 208 | } 209 | else { 210 | playSound(baseURL + 'hit1'); 211 | addSomeRandom(); 212 | } 213 | } 214 | 215 | if (ballY >= popups.length) { 216 | loseLife(); 217 | } 218 | else if (ballY < 1) { 219 | ballYV = ballSpeed; 220 | addSomeRandom(); 221 | } 222 | else if (y == popups.length - 1 && Math.floor(ballX) >= Math.floor(paddleX) && Math.floor(ballX) < Math.floor(paddleX) + paddleSize) { 223 | ballYV = -ballSpeed; 224 | playSound(baseURL + 'hit2'); 225 | addSomeRandom(); 226 | } 227 | else if (ballX < 0 || ballX >= levelWidth) { 228 | ballXV *= -1; 229 | addSomeRandom(); 230 | } 231 | 232 | ballX = Math.max(0, Math.min(levelWidth - .01, ballX)); 233 | } 234 | 235 | function loop() { 236 | var now = performance.now(); 237 | 238 | if (running) { 239 | movePaddle(); 240 | moveBall(); 241 | } 242 | 243 | if (gameoverTime) { 244 | statusLine = toFullWidth('⠀Score:' + score + '⠀GAME⠀OVER'); 245 | } 246 | else if (!positions.length) { 247 | statusLine = toFullWidth('⠀Score:' + score + '⠀Lives:' + lives); 248 | } 249 | else { 250 | statusLine = toFullWidth('⠀⠀---Level:' + level + '---'); 251 | } 252 | 253 | render(); 254 | 255 | setTimeout(loop, 1000/30); 256 | } 257 | 258 | function closeWindows() { 259 | var popup; 260 | 261 | running = false; 262 | 263 | while (popups.length) { 264 | popup = popups.shift(); 265 | popup.close(); 266 | } 267 | } 268 | 269 | function setup() { 270 | var split = location.href.split('/'); 271 | split.pop(); 272 | baseURL = split.join('/') + '/'; 273 | 274 | document.addEventListener('keydown', function (event) { 275 | keys[event.which] = true; 276 | }); 277 | 278 | document.addEventListener('keyup', function (event) { 279 | keys[event.which] = false; 280 | }); 281 | 282 | document.title = '-'; 283 | 284 | closeButton = document.createElement('button'); 285 | closeButton.innerHTML = 'close'; 286 | closeButton.addEventListener('click', closeWindows); 287 | document.body.appendChild(closeButton); 288 | 289 | setupLevel(); 290 | startBall(); 291 | loop(); 292 | 293 | popups.forEach(function (popup) { 294 | popup.history.replaceState({}, '', '/'); 295 | }); 296 | } 297 | -------------------------------------------------------------------------------- /ded.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewRayfield/url-bar-games/a268775abec4b6a0278eae0e7b37d0b5b334858e/ded.wav -------------------------------------------------------------------------------- /dk-bacmusic.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewRayfield/url-bar-games/a268775abec4b6a0278eae0e7b37d0b5b334858e/dk-bacmusic.wav -------------------------------------------------------------------------------- /dk-death.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewRayfield/url-bar-games/a268775abec4b6a0278eae0e7b37d0b5b334858e/dk-death.wav -------------------------------------------------------------------------------- /dk-hammertime.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewRayfield/url-bar-games/a268775abec4b6a0278eae0e7b37d0b5b334858e/dk-hammertime.wav -------------------------------------------------------------------------------- /dk-howhigh.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewRayfield/url-bar-games/a268775abec4b6a0278eae0e7b37d0b5b334858e/dk-howhigh.wav -------------------------------------------------------------------------------- /dk-levelend.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewRayfield/url-bar-games/a268775abec4b6a0278eae0e7b37d0b5b334858e/dk-levelend.wav -------------------------------------------------------------------------------- /dk-smash3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewRayfield/url-bar-games/a268775abec4b6a0278eae0e7b37d0b5b334858e/dk-smash3.wav -------------------------------------------------------------------------------- /dk-walking.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewRayfield/url-bar-games/a268775abec4b6a0278eae0e7b37d0b5b334858e/dk-walking.wav -------------------------------------------------------------------------------- /donkey-kong.js: -------------------------------------------------------------------------------- 1 | var popups = [], 2 | keys = {}, 3 | 4 | pauline = ['💃', '🕺', '🍔'][Math.floor(Math.random()*3)], 5 | 6 | level = 1, 7 | lives = 3, 8 | 9 | levelHeight = 7, 10 | levelWidth = 15, 11 | 12 | popupWidth = window.screen.width, 13 | popupHeight = 50, 14 | popupGap = 50, 15 | 16 | didMove = false, 17 | 18 | playerX = 0, 19 | playerY = levelHeight - 1, 20 | death = false, 21 | 22 | barrels = [], 23 | barrelMap = {}, 24 | barrelSpeed = 150, 25 | barrelRate = 5000, 26 | barrelBaseRate = 3000, 27 | 28 | nextBarrelAdd = 0, 29 | lastBarrelMove = 0, 30 | lastPlayerMove = 0, 31 | 32 | levelWon = false, 33 | levelEndTime, 34 | 35 | showingLevel = false, 36 | gameover = false, 37 | running = false, 38 | 39 | hammering = false, 40 | hammerX, 41 | 42 | closeButton, 43 | 44 | backgroundAudio, 45 | walkingAudio, 46 | hammeringAudio, 47 | 48 | baseURL; 49 | 50 | var map = [ 51 | ' '.split(''), 52 | ' 1 '.split(''), 53 | ' 2 1 '.split(''), 54 | '1 1 '.split(''), 55 | ' 1 1 '.split(''), 56 | '1 1 '.split(''), 57 | ' 1 '.split(''), 58 | ]; 59 | 60 | 61 | function render() { 62 | var timeTo, 63 | barrelShown = false, 64 | paulineShown = true, 65 | gorillaX = 2, gorillaY = 1; 66 | 67 | if (levelWon) { 68 | timeTo = levelEndTime - performance.now(); 69 | 70 | if (Math.floor(timeTo/800) >= 4) { 71 | gorillaX = 3; 72 | } 73 | else if (Math.floor(timeTo/800) == 3) { 74 | gorillaX = 4; 75 | } 76 | else if (Math.floor(timeTo/800) == 2) { 77 | gorillaX = 5; 78 | } 79 | else if (Math.floor(timeTo/800) == 1) { 80 | gorillaX = 5; 81 | gorillaY = 0; 82 | paulineShown = false; 83 | } 84 | else if (Math.floor(timeTo/800) <= 0) { 85 | gorillaX = 5; 86 | gorillaY = -1; 87 | paulineShown = false; 88 | } 89 | } 90 | else { 91 | timeTo = nextBarrelAdd - performance.now(); 92 | 93 | if (timeTo < 5000 && timeTo > 4000) { 94 | barrelShown = true; 95 | } 96 | if (timeTo < 4000 && timeTo > 3000) { 97 | barrelShown = true; 98 | } 99 | if (timeTo < 3000 && timeTo > 2000) { 100 | barrelShown = true; 101 | gorillaX = 1; 102 | } 103 | if (timeTo < 2000 && timeTo > 1000) { 104 | gorillaX = 1; 105 | } 106 | } 107 | 108 | popups.forEach(function (popup, y) { 109 | var s = '', x; 110 | 111 | if (!popup.document.location) return; 112 | 113 | if (showingLevel) { 114 | if (y == 1) { 115 | for (x = 0; x < levelWidth; x ++) { 116 | if ((Math.floor(performance.now()/400) + x) % 2) { 117 | s += '🔺'; 118 | } 119 | else { 120 | s += '🔻'; 121 | } 122 | } 123 | } 124 | else if (y == 2) { 125 | s = toFullWidth('⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀LEVEL:' + level); 126 | } 127 | else if (y == 3) { 128 | s = toFullWidth('⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀LIVES:' + lives); 129 | } 130 | else if (y == 4) { 131 | for (x = 0; x < levelWidth; x ++) { 132 | if ((Math.floor(performance.now()/400) + x) % 2) { 133 | s += '🔻'; 134 | } 135 | else { 136 | s += '🔺'; 137 | } 138 | } 139 | } 140 | else { 141 | s = ''; 142 | } 143 | 144 | popup.document.location.hash = s; 145 | } 146 | else if (gameover) { 147 | if (y == 1) { 148 | for (x = 0; x < levelWidth; x ++) { 149 | if ((Math.floor(performance.now()/200) % levelWidth) == levelWidth - x) { 150 | s += '🦍'; 151 | } 152 | else { 153 | s += '💀'; 154 | } 155 | } 156 | } 157 | else if (y == 2) { 158 | s = toFullWidth('⠀⠀⠀⠀⠀⠀⠀⠀⠀GAME⠀OVER'); 159 | } 160 | else if (y == 3) { 161 | s = toFullWidth('⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀LEVEL:' + level); 162 | } 163 | else if (y == 4) { 164 | for (x = 0; x < levelWidth; x ++) { 165 | if ((Math.floor(performance.now()/200) % levelWidth) == x) { 166 | s += '🦍'; 167 | } 168 | else { 169 | s += '💀'; 170 | } 171 | } 172 | } 173 | else { 174 | s = ''; 175 | } 176 | 177 | popup.document.location.hash = s; 178 | } 179 | else { 180 | for (x = 0; x < levelWidth; x ++) { 181 | if (y == Math.floor(playerY) && x == Math.floor(playerX)) { 182 | if (death) { 183 | if (Math.floor(performance.now()/400) % 2) { 184 | s += '💀'; 185 | } 186 | else { 187 | s += '🚶'; 188 | } 189 | } 190 | else { 191 | if (didMove) { 192 | if (Math.floor(performance.now()/200) % 2) { 193 | s += '🚶'; 194 | } 195 | else { 196 | s += '🏃'; 197 | } 198 | } 199 | else { 200 | s += '🚶'; 201 | } 202 | } 203 | } 204 | else if (hammering && y == playerY && x == hammerX /*&& Math.floor(performance.now()/100) % 2*/) { 205 | s += '🔨'; 206 | } 207 | else if (y == gorillaY && x == gorillaX) { 208 | s += '🦍'; 209 | } 210 | else if (y == 1 && x == 0 && barrelShown) { 211 | s += '🛢'; 212 | } 213 | else if (barrelMap[x+','+y]) { 214 | s += '🔴'; 215 | } 216 | else if (y == 0 && (x < 5 || x > 9)) { 217 | s += '🔶'; 218 | } 219 | else if (paulineShown && y == 0 && x == 6) { 220 | s += pauline; 221 | } 222 | else if (levelWon && y == 0 && x == 7) { 223 | if (Math.floor(performance.now()/400) % 2) { 224 | s += paulineShown ? '💖' : '💔'; 225 | } 226 | else { 227 | s += paulineShown ? '💕' : '⬜'; 228 | } 229 | } 230 | else { 231 | if (map[y][x] == '1') s += '⬆'; 232 | else if (map[y][x] == '2') s += '🔨'; 233 | else s += '⬜'; 234 | } 235 | } 236 | 237 | popup.document.location.hash = '🔶' + s + '🔶'; 238 | } 239 | 240 | }); 241 | } 242 | 243 | function movePlayer() { 244 | var xMove = 0, yMove = 0; 245 | 246 | didMove = false; 247 | 248 | if (keys[37]) { 249 | didMove = true; 250 | playerX --; // left 251 | hammerX = playerX - 1; 252 | } 253 | if (keys[39]) { 254 | didMove = true; 255 | playerX ++; // right 256 | hammerX = playerX + 1; 257 | } 258 | 259 | if (keys[38]) { 260 | if (!hammering && map[Math.floor(playerY)][Math.floor(playerX)] == '1') { 261 | didMove = true; 262 | playerY --; // up 263 | } 264 | } 265 | if (keys[40]) { 266 | if (Math.floor(playerY) < levelHeight - 1) { 267 | if (!hammering && map[Math.floor(playerY)+1][Math.floor(playerX)] == '1') { 268 | didMove = true; 269 | playerY ++; // down 270 | } 271 | } 272 | } 273 | 274 | if (playerX < 0) playerX = 0; 275 | else if (playerX >= levelWidth) playerX = levelWidth - 1; 276 | 277 | if (playerY < 0) playerY = 0; 278 | else if (playerY >= levelHeight) playerY = levelHeight - 1; 279 | 280 | if (didMove) { 281 | walkingAudio.volume = 1; 282 | lastPlayerMove = performance.now(); 283 | } 284 | else { 285 | walkingAudio.volume = 0; 286 | } 287 | 288 | if (map[Math.floor(playerY)][Math.floor(playerX)] == '2') { 289 | map[Math.floor(playerY)][Math.floor(playerX)] = '3'; 290 | 291 | hammering = true; 292 | 293 | hammeringAudio.currentTime = 0; 294 | hammeringAudio.volume = 1; 295 | 296 | setTimeout(function () { 297 | hammering = false; 298 | }, 9000); 299 | } 300 | 301 | if (playerY == 0) { 302 | playSound(baseURL + 'dk-levelend'); 303 | levelWon = true; 304 | running = false; 305 | levelEndTime = performance.now() + 4000; 306 | setTimeout(function () { 307 | levelWon = false; 308 | nextLevel(); 309 | setupLevel(); 310 | showLevel(); 311 | }, 4000); 312 | } 313 | } 314 | 315 | function moveBarrels() { 316 | var freshBarrels = []; 317 | 318 | barrelMap = {}; 319 | 320 | barrels.forEach(function (barrel) { 321 | if (barrel.d == 1) { 322 | if (barrel.x >= levelWidth - 1) { 323 | barrel.y ++; 324 | barrel.d = 0; 325 | } 326 | else { 327 | barrel.x ++; 328 | } 329 | } 330 | else { 331 | if (barrel.x <= 0) { 332 | barrel.y ++; 333 | barrel.d = 1; 334 | } 335 | else { 336 | barrel.x --; 337 | } 338 | } 339 | 340 | if (barrel.y < levelHeight) { 341 | barrelMap[barrel.x+','+barrel.y] = true; 342 | freshBarrels.push(barrel); 343 | } 344 | }); 345 | 346 | barrels = freshBarrels; 347 | 348 | lastBarrelMove = performance.now(); 349 | } 350 | 351 | function addBarrel() { 352 | barrels.push({x:2, y:1, d:1}); 353 | 354 | nextBarrelAdd = performance.now() + barrelBaseRate + (Math.random() * barrelRate); 355 | } 356 | 357 | function checkDeath() { 358 | if (barrelMap[Math.floor(playerX) +','+ Math.floor(playerY)]) { 359 | hammering = false; 360 | running = false; 361 | lives --; 362 | death = true; 363 | playSound(baseURL + 'dk-death'); 364 | 365 | setTimeout(function () { 366 | if (lives <= 0) { 367 | gameover = true; 368 | } 369 | else { 370 | death = false; 371 | setupLevel(); 372 | showLevel(); 373 | } 374 | }, 5000); 375 | } 376 | } 377 | 378 | function checkSmash() { 379 | var freshBarrels; 380 | 381 | if (hammering) { 382 | console.log(barrelMap[Math.floor(hammerX) +','+ Math.floor(playerY)]); 383 | if (barrelMap[Math.floor(hammerX) +','+ Math.floor(playerY)]) { 384 | playSound(baseURL + 'dk-smash3', .3); 385 | 386 | barrelMap = {}; 387 | freshBarrels = []; 388 | 389 | barrels.forEach(function (barrel) { 390 | if (barrel.x != Math.floor(hammerX) || barrel.y != Math.floor(playerY)) { 391 | barrelMap[barrel.x+','+barrel.y] = true; 392 | freshBarrels.push(barrel); 393 | } 394 | }); 395 | 396 | barrels = freshBarrels; 397 | } 398 | } 399 | } 400 | 401 | function loop() { 402 | var now = performance.now(); 403 | 404 | if (running) { 405 | if (hammering) { 406 | hammeringAudio.volume = 1; 407 | backgroundAudio.volume = 0; 408 | } 409 | else { 410 | hammeringAudio.volume = 0; 411 | backgroundAudio.volume = 1; 412 | } 413 | 414 | if (now - lastPlayerMove >= 200) { 415 | movePlayer(); 416 | checkSmash(); 417 | checkDeath(); 418 | } 419 | if (now - lastBarrelMove >= barrelSpeed) { 420 | moveBarrels(); 421 | checkSmash(); 422 | checkDeath(); 423 | } 424 | if (now > nextBarrelAdd) addBarrel(); 425 | } 426 | else { 427 | hammeringAudio.volume = 0; 428 | backgroundAudio.volume = 0; 429 | walkingAudio.volume = 0; 430 | } 431 | 432 | render(); 433 | 434 | setTimeout(loop, 1000/30); 435 | } 436 | 437 | function nextLevel() { 438 | var i, l, x, y; 439 | 440 | level ++; 441 | 442 | barrelRate -= 500; 443 | if (barrelBaseRate > 1000) { 444 | barrelBaseRate -= 250; 445 | } 446 | 447 | map.forEach(function (line, y) { 448 | var r, x; 449 | 450 | if (y == 0 || y == 1) return; 451 | 452 | if (y == 2) { 453 | r = 4 + Math.floor(Math.random() * (levelWidth-4)); 454 | } 455 | else { 456 | r = Math.floor(Math.random() * levelWidth); 457 | } 458 | 459 | for (x = 0; x < levelWidth; x ++) { 460 | line[x] = x == r ? '1' : ' '; 461 | } 462 | }); 463 | 464 | if (level <= 3) l = 2; 465 | else if (level <= 5) l = 1; 466 | 467 | for (i = 0; i < l; i ++) { 468 | map[Math.floor(Math.random()*(levelHeight - 2))+2][Math.floor(Math.random()*levelWidth)] = '1'; 469 | } 470 | 471 | if (level <= 5) { 472 | do { 473 | y = Math.floor(Math.random()*(levelHeight - 2))+2; 474 | x = Math.floor(Math.random()*levelWidth); 475 | } 476 | while (map[y][x] == '1'); 477 | 478 | map[y][x] = '2'; 479 | } 480 | } 481 | 482 | function setupLevel() { 483 | map.forEach(function (line) { 484 | var i; 485 | 486 | for (i = 0; i < line.length; i ++) { 487 | if (line[i] == '3') line[i] = '2'; 488 | } 489 | }); 490 | 491 | playerX = 0; 492 | playerY = levelHeight - 1; 493 | barrels = []; 494 | barrelMap = {}; 495 | lastBarrelMove = 0; 496 | lastPlayerMove = 0; 497 | running = true; 498 | } 499 | 500 | function showLevel() { 501 | playSound(baseURL + 'dk-howhigh'); 502 | showingLevel = true; 503 | running = false; 504 | setTimeout(function () { 505 | showingLevel = false; 506 | running = true; 507 | }, 2500); 508 | } 509 | 510 | function closeWindows() { 511 | var popup; 512 | 513 | running = false; 514 | 515 | while (popups.length) { 516 | popup = popups.shift(); 517 | popup.close(); 518 | } 519 | } 520 | 521 | function setup() { 522 | var split = location.href.split('/'); 523 | split.pop(); 524 | baseURL = split.join('/') + '/'; 525 | 526 | document.addEventListener('keydown', function (event) { 527 | keys[event.which] = true; 528 | }); 529 | 530 | document.addEventListener('keyup', function (event) { 531 | keys[event.which] = false; 532 | }); 533 | 534 | document.title = '-'; 535 | 536 | closeButton = document.createElement('button'); 537 | closeButton.innerHTML = 'close'; 538 | closeButton.addEventListener('click', closeWindows); 539 | document.body.appendChild(closeButton); 540 | 541 | walkingAudio = playSound(baseURL + 'dk-walking', 0); 542 | walkingAudio.loop = true; 543 | backgroundAudio = playSound(baseURL + 'dk-bacmusic', 0); 544 | backgroundAudio.loop = true; 545 | hammeringAudio = playSound(baseURL + 'dk-hammertime', 0); 546 | hammeringAudio.loop = true; 547 | 548 | setupLevel(); 549 | showLevel(); 550 | loop(); 551 | 552 | popups.forEach(function (popup) { 553 | popup.history.replaceState({}, '', '/'); 554 | }); 555 | } 556 | -------------------------------------------------------------------------------- /face.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewRayfield/url-bar-games/a268775abec4b6a0278eae0e7b37d0b5b334858e/face.png -------------------------------------------------------------------------------- /hit1.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewRayfield/url-bar-games/a268775abec4b6a0278eae0e7b37d0b5b334858e/hit1.wav -------------------------------------------------------------------------------- /hit2.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewRayfield/url-bar-games/a268775abec4b6a0278eae0e7b37d0b5b334858e/hit2.wav -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 77 | -------------------------------------------------------------------------------- /over.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewRayfield/url-bar-games/a268775abec4b6a0278eae0e7b37d0b5b334858e/over.wav -------------------------------------------------------------------------------- /popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 17 | 18 | -------------------------------------------------------------------------------- /renderer.js: -------------------------------------------------------------------------------- 1 | function Renderer() { 2 | var self = this, 3 | container = document.getElementById('container'); 4 | 5 | self.tRenderer = new THREE.WebGLRenderer({alpha: false, antialias: true}); 6 | container.appendChild(self.tRenderer.domElement); 7 | 8 | self.scene = new THREE.Scene(); 9 | 10 | self.setSize = function (width, height) { 11 | self.width = width; 12 | self.height = height; 13 | 14 | self.tRenderer.setSize(self.width, self.height); 15 | 16 | self.renderTarget = new THREE.WebGLRenderTarget(self.width/10, self.height/10, {minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter}); 17 | self.camera = new THREE.PerspectiveCamera(70, self.width / self.height, 1, 1000); 18 | }; 19 | 20 | self.setSize(500, 200); 21 | 22 | self.render = function render() { 23 | self.tRenderer.render(self.scene, self.camera); 24 | self.tRenderer.render(self.scene, self.camera, self.renderTarget); 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /utils.js: -------------------------------------------------------------------------------- 1 | function toFullWidth(input) { 2 | var lookup = {"`" : "`","1" : "1","2" : "2","3" : "3","4" : "4","5" : "5","6" : "6","7" : "7","8" : "8","9" : "9","0" : "0","-" : "-","=" : "=","~" : "~","!" : "!","@" : "@","#" : "#","$" : "$","%" : "%","^" : "^","&" : "&","*" : "*","(" : "(",")" : ")","_" : "_","+" : "+","q" : "q","w" : "w","e" : "e","r" : "r","t" : "t","y" : "y","u" : "u","i" : "i","o" : "o","p" : "p","[" : "[","]" : "]","\\" : "\\","Q" : "Q","W" : "W","E" : "E","R" : "R","T" : "T","Y" : "Y","U" : "U","I" : "I","O" : "O","P" : "P","{" : "{","}" : "}","|" : "|","a" : "a","s" : "s","d" : "d","f" : "f","g" : "g","h" : "h","j" : "j","k" : "k","l" : "l",";" : ";","'" : "'","A" : "A","S" : "S","D" : "D","F" : "F","G" : "G","H" : "H","J" : "J","K" : "K","L" : "L",":" : ":","\"" : "\"","z" : "z","x" : "x","c" : "c","v" : "v","b" : "b","n" : "n","m" : "m","," : ",","." : ".","/" : "/","Z" : "Z","X" : "X","C" : "C","V" : "V","B" : "B","N" : "N","M" : "M","<" : "<",">" : ">","?" : "?", " ": " "}, 3 | output = ''; 4 | 5 | input.split('').forEach(function (c) { 6 | if (lookup[c]) output += lookup[c]; 7 | else output += c; 8 | }); 9 | 10 | return output; 11 | } 12 | 13 | function playSound(fileName, volume) { 14 | var audio; 15 | 16 | if (volume == undefined) volume = 1; 17 | if (volume > 1) volume = 1; 18 | 19 | audio = new (Audio)(fileName + '.wav'); 20 | audio.volume = volume; 21 | 22 | audio.play(); 23 | 24 | return audio; 25 | } 26 | 27 | function degToRad(degrees) { 28 | return degrees * (Math.PI / 180); 29 | } 30 | function radToDeg(radians) { 31 | return radians * (180 / Math.PI); 32 | } 33 | 34 | function rotateCoord(coords, angle) { 35 | var x = coords.x, y = coords.y; 36 | var radians = degToRad(angle), 37 | cos = Math.cos(radians), 38 | sin = Math.sin(radians), 39 | nx = (cos * x) + (sin * y), 40 | ny = (cos * y) - (sin * x); 41 | 42 | return {x: nx, y: ny}; 43 | } 44 | -------------------------------------------------------------------------------- /wavy.js: -------------------------------------------------------------------------------- 1 | var popups = []; 2 | 3 | function loop() { 4 | popups.forEach(function (popup, y) { 5 | var i, 6 | s = '#', 7 | l = Math.round(Math.sin(performance.now()/200 + (y/2)) * 5) + 5; 8 | 9 | s += String.fromCharCode(0x2588); 10 | 11 | for (i = 0; i < l; i ++) { 12 | //s += String.fromCharCode(0x2581); 13 | s += String.fromCharCode(0x2588); 14 | } 15 | 16 | //s += 'x'; 17 | 18 | popup.document.location.hash = s; 19 | }); 20 | 21 | setTimeout(loop, 1000/20); 22 | } 23 | 24 | function closeWindows() { 25 | var popup; 26 | 27 | running = false; 28 | 29 | while (popups.length) { 30 | popup = popups.shift(); 31 | popup.close(); 32 | } 33 | } 34 | 35 | function setup() { 36 | var closeButton; 37 | 38 | closeButton = document.createElement('button'); 39 | closeButton.innerHTML = 'close'; 40 | closeButton.addEventListener('click', closeWindows); 41 | document.body.appendChild(closeButton); 42 | 43 | loop(); 44 | 45 | /*popups.forEach(function (popup) { 46 | popup.history.replaceState({}, '', '/'); 47 | });*/ 48 | } 49 | -------------------------------------------------------------------------------- /webcam.js: -------------------------------------------------------------------------------- 1 | var popups = [], 2 | video = document.createElement('video'), 3 | canvas = document.createElement('canvas'), 4 | context = canvas.getContext('2d'), 5 | vWidth, vHeight, 6 | oWidth, oHeight, 7 | palette; 8 | 9 | function loop() { 10 | var x, y, i, r, g, b; 11 | 12 | context.drawImage(video, 0, 0, oWidth, oHeight); 13 | data = context.getImageData(0, 0, oWidth, oHeight).data; 14 | 15 | popups.forEach(function (popup, y) { 16 | var s = ''; 17 | 18 | y *= 2; 19 | 20 | for (x = 0; x < oWidth; x ++) { 21 | i = 4 * ((y * oWidth) + x); 22 | 23 | r = Math.floor(data[i + 0] / 16); 24 | g = Math.floor(data[i + 1] / 16); 25 | b = Math.floor(data[i + 2] / 16); 26 | 27 | s += palette[r][g][b].s; 28 | } 29 | 30 | popup.document.location.hash = s; 31 | }); 32 | 33 | setTimeout(loop, 1000/10); 34 | } 35 | 36 | function closeWindows() { 37 | var popup; 38 | 39 | running = false; 40 | 41 | while (popups.length) { 42 | popup = popups.shift(); 43 | popup.close(); 44 | } 45 | } 46 | 47 | function setup() { 48 | var xhr = new XMLHttpRequest(); 49 | 50 | closeButton = document.createElement('button'); 51 | closeButton.innerHTML = 'close'; 52 | closeButton.addEventListener('click', closeWindows); 53 | document.body.appendChild(closeButton); 54 | 55 | xhr.open('GET', 'palette.json'); 56 | xhr.addEventListener('readystatechange', function () { 57 | if (xhr.readyState == 4) { 58 | palette = JSON.parse(xhr.responseText); 59 | 60 | if (navigator.mediaDevices.getUserMedia) { 61 | navigator.mediaDevices.getUserMedia({video: true}) 62 | .then(function (stream) { 63 | video.srcObject = stream; 64 | video.play(); 65 | 66 | setTimeout(function () { 67 | vWidth = video.videoWidth || video.naturalWidth || video.width; 68 | vHeight = video.videoHeight || video.naturalHeight || video.height; 69 | 70 | oHeight = popups.length * 2; 71 | oWidth = Math.floor((vWidth/vHeight) * oHeight); 72 | 73 | canvas.width = oWidth; 74 | canvas.height = oHeight; 75 | 76 | loop(); 77 | }, 1000); 78 | }) 79 | .catch(function (error) { 80 | console.log("Something went wrong!"); 81 | }); 82 | } 83 | } 84 | }); 85 | xhr.send(); 86 | 87 | popups.forEach(function (popup) { 88 | popup.history.replaceState({}, '', '/'); 89 | }); 90 | } 91 | -------------------------------------------------------------------------------- /win.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MatthewRayfield/url-bar-games/a268775abec4b6a0278eae0e7b37d0b5b334858e/win.wav --------------------------------------------------------------------------------