diff --git a/hug/hug.js b/hug/hug.js new file mode 100644 index 0000000..128e049 --- /dev/null +++ b/hug/hug.js @@ -0,0 +1,236 @@ +var main = document.getElementById('main'); +var hearts = document.getElementById('hearts'); + +var levels = [ + "get a lil' hug!", + 'get a biiig hug!', + 'time to smile 😊', + 'landing on planet hug' +] + +var hugsies = [ + [ + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ 1, '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ 1, '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ 1, 1, 1, '', '', -1, '', '', 1, '', '', 1, 1, 1, ], + [ 1, '', '', 1, '', 1, '', '', 1, '', 1, '', '', 1, ], + [ 1, '', '', 1, '', 1, '', '', 2, '', 1, '', '', 1, ], + [ 1, '', '', 1, '', '', 1, 1, '', '', '', 1, 1, 1, ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', 1, ], + [ '', '', '', '', '', '', '', '', '', '', 1, '', '', 1, ], + [ '', '', '', '', '', '', '', '', '', '', '', 1, 1, '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + ], + [ + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ -1, '', '', 4, '', 6, '', '', 7, '', '', 8, 8, '', ], + [ 3, '', '', 4, '', 7, '', '', 6, '', 8, '', '', '', ], + [ 3, '', '', 4, '', 6, '', '', 7, '', 8, '', '', '', ], + [ 3, 5, 5, 4, '', 7, '', '', 6, '', 9, '', 8, 8, ], + [ 3, '', '', 4, '', 6, '', '', 7, '', 8, '', '', 8, ], + [ 3, '', '', 4, '', 7, '', '', 6, '', 8, '', '', 8, ], + [ 3, '', '', 4, '', '', 6, 7, '', '', '', 8, 8, '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + ], + [ + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ '', '', '', '', 10, '', '', '', 11, '', '', '', '', '', ], + [ '', '', '', '', -1, '', '', '', 11, '', '', '', '', '', ], + [ '', '', '', '', 10, '', '', '', 11, '', '', '', '', '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ '', '', 12, '', '', '', '', '', '', '', 18, '', '', '', ], + [ '', '', '', 13, '', '', '', '', '', 17, '', '', '', '', ], + [ '', '', '', '', 14, 13, 15, 16, 15, '', '', '', '', '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + ], + [ + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + [ '', '', '', '', 22, 26, 26, 20, 20, 20, '', '', '', '', ], + [ '', '', '', 26, 26, 26, 26, 26, 20, 20, 20, '', '', '', ], + [ '', '', 25, 25, 26, 26, 26, 26, 26, 26, 20, 20, '', '', ], + [ '', 25, 25, 25, 26, 26, 21, 26, 19, 26, 26, 26, 26, '', ], + [ '', 25, 25, 26, 26, 26, 26, -1, 19, 19, 19, 26, 19, '', ], + [ '', 25, 26, 26, 26, 26, 19, 19, 19, 19, 19, 19, 19, '', ], + [ '', 26, 26, 26, 26, 26, 26, 26, 26, 19, 19, 19, 19, '', ], + [ '', 23, 23, 26, 26, 24, 24, 24, 26, 24, 26, 26, 26, '', ], + [ '', '', 23, 26, 24, 24, 24, 24, 24, 24, 26, 24, '', '', ], + [ '', '', '', 26, 24, 24, 24, 26, 24, 24, 24, '', '', '', ], + [ '', '', '', '', 24, 24, 26, 26, 26, 24, '', '', '', '', ], + [ '', '', '', '', '', '', '', '', '', '', '', '', '', '', ], + ], +]; + +var table; + +var session = 0; +var kiss = 1; + +var cells = []; + +function makeCells() { + cells = []; + table = document.createElement('table'); + main.appendChild(table); + for (var y = 0; y < hugsies[session].length; y++) { + var tr = document.createElement('tr'); + table.appendChild(tr); + cells.push([]); + for (var x = 0; x < hugsies[session][y].length; x++) { + var td = document.createElement('td'); + tr.appendChild(td); + cells[y][x] = td; + } + } +} + +function offset(e) { + var top = 0; + var left = 0; + while (e) { + top += e.offsetTop; + left += e.offsetLeft; + e = e.offsetParent; + } + return { top: top, left: left }; +} + +function max() { + return Math.max.apply(Math, hugsies[session].map(function (row) { return Math.max.apply(Math, row); })); +} + +function mini(session) { + for (var y = 0; y < hugsies[session].length; y++) { + for (var x = 0; x < hugsies[session][y].length; x++) { + if (hugsies[session][y][x] == -1) { + return { y: y, x: x }; + } + } + } +} + +function nextSession() { + cuddle(); + session++; + if (session >= hugsies.length) { + session = 0; + kiss = 1; + }; + + window.setTimeout(function() { + var futureMini = mini(session); + var destOffset = offset(cells[futureMini.y][futureMini.x]); + var currentOffset = offset(table); + + var scale = 'scale(calc(1 / ' + Math.max(cells.length, cells[0].length) + '))'; + + table.style.transform = 'translate('+(destOffset.left - currentOffset.left)+'px,'+(destOffset.top-currentOffset.top)+'px) ' + scale; + + window.setTimeout(function() { + var miniTable = table; + makeCells(); + cuddle(); + + for (var y = 0; y < cells.length; y++) { + for (var x = 0; x < cells[y].length; x++) { + cells[y][x].style.opacity = 0; + window.setTimeout((function(c) { return function() { c.style.opacity = 1; } })(cells[y][x]), Math.sqrt(y*y + x*x) * 100) + } + } + + var miniyx = mini(session); + + cells[miniyx.y][miniyx.x].innerText = ''; + cells[miniyx.y][miniyx.x].appendChild(miniTable); + miniTable.style.transform = scale; + miniTable.style.position = 'absolute'; + var nested = miniTable.getElementsByTagName('table'); + for (var i = 0; i < nested.length; i++) { + if (nested[i] != miniTable) { + nested[i].parentElement.innerHTML = '🤗'; + } + } + cells[miniyx.y][miniyx.x].className = 'on mini'; + cells[miniyx.y][miniyx.x].style.opacity = 1; + }, 3000); + }, 1000); +} + +var pauseKiss = 0; +var mouse = { x: 0, y: 0 } +var timeout = false; +var kisses = 0; + +function muah() { kiss++; if (kiss >= max()) { pauseKiss = Date.now() + 3000; window.clearTimeout(timeout); nextSession(); } else { cuddle(); } } +function blowKiss(e) { + if (Date.now() > pauseKiss) { + var heart = document.createElement('div'); + hearts.appendChild(heart); + var emojis = ['❤️', '♥️', '💗', '<3', '💖', '💛', '💙', '💜', '💚', '💞', '💝', '💌', '💕']; + heart.innerText = emojis[Math.floor(Math.random() * emojis.length)]; + heart.style.position = 'absolute'; + heart.style.top = mouse.y + 'px'; + heart.style.left = mouse.x + 'px'; + + if (timeout) { window.clearInterval (timeout) }; + kisses++; + if (kisses > 5) { + pauseKiss = Date.now() + 4000; + kisses = 0; + } + timeout = window.setTimeout(blowKiss, 300 + Math.random() * 700) + } else { + timeout = window.setTimeout(blowKiss, pauseKiss - Date.now() + 100); + } +} +function blowKissEnter(e) { blowKissMove(e); blowKiss(); } +function blowKissLeave() { if (timeout) { window.clearTimeout(timeout) }; } +function blowKissMove(e) { mouse = { x: e.clientX, y: e.clientY }; } + + +function cuddle() { + document.getElementById('level').innerText = levels[session]; + for (var y = 0; y < hugsies[session].length; y++) { + for (var x = 0; x < hugsies[session][y].length; x++) { + var td = cells[y][x]; + var classy = []; + var emoji = '🤗'; + if (hugsies[session][y][x] == 26) { emoji = '💙'; } + if (hugsies[session][y][x] == 0 || hugsies[session][y][x] > kiss) { + classy.push('off'); + } else { + classy.push('on'); + } + if (hugsies[session][y][x] == kiss + 1) { + classy.push('next'); + emoji = '😘'; + td.addEventListener('click', muah); + td.addEventListener('mousemove', blowKissMove); + td.addEventListener('mouseleave', blowKissLeave); + td.addEventListener('mouseenter', blowKissEnter); + } else { + td.removeEventListener('click', muah); + td.removeEventListener('mousemove', blowKissMove); + td.removeEventListener('mouseleave', blowKissLeave); + td.removeEventListener('mouseenter', blowKissEnter); + } + if (td.getElementsByTagName('table').length == 0) { + td.className = classy.join(' '); + td.innerText = emoji; + } + } + } +} + +makeCells(); +cuddle(); \ No newline at end of file diff --git a/hug/index.html b/hug/index.html new file mode 100644 index 0000000..e8e42b9 --- /dev/null +++ b/hug/index.html @@ -0,0 +1,76 @@ +<!DOCTYPE html> +<html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + <title>Hug?</title> + <style> + html, body { height: 100%; padding: 0; margin: 0; } + body { font-size: 2em; display: grid; justify-items: center; align-content: center; } + #main { } + table { transition: transform 3s cubic-bezier(1,0,0.5,1); transform-origin: top left; } + table, tr, td { border: none; padding: 0; } + td { position: relative; } + td { cursor: default; transition: filter 1s ease-in-out, opacity 1s ease-in-out; filter: grayscale(100%) brightness(50%) blur(0.3em); } + td.on { filter: grayscale(0%) brightness(100%) blur(0em); } + td.mini { vertical-align: top; } + td.next { cursor: pointer; filter: grayscale(100%) brightness(100%) blur(0.3em); } + td.next:hover { cursor: pointer; filter: grayscale(0%) brightness(100%) blur(0em); } + #hearts * { color: pink; font-weight: bold; font-family: monospace; opacity: 0; } + #hearts :nth-child(3n+0) { animation: flutter0 3s linear; } + #hearts :nth-child(3n+1) { animation: flutter1 3.2s linear; } + #hearts :nth-child(3n+2) { animation: flutter2 3.3s linear; } + #hearts { pointer-events: none; } + @keyframes flutter0 { + 0% { opacity: 0.9; transform: translate( 0.00em, 0.00em) scale(1.00); } + 10% { opacity: 0.9; transform: translate( 0.17em, -1.36em) scale(1.46); } + 20% { opacity: 0.9; transform: translate( 0.36em, -2.64em) scale(1.55); } + 30% { opacity: 0.9; transform: translate( 0.08em, -3.84em) scale(1.09); } + 40% { opacity: 0.9; transform: translate(-0.61em, -4.96em) scale(0.47); } + 50% { opacity: 0.9; transform: translate(-0.96em, -6.00em) scale(0.28); } + 60% { opacity: 0.9; transform: translate(-0.34em, -6.96em) scale(0.78); } + 70% { opacity: 0.9; transform: translate( 0.92em, -7.84em) scale(1.56); } + 80% { opacity: 0.9; transform: translate( 1.58em, -8.64em) scale(1.89); } + 90% { opacity: 0.6; transform: translate( 0.74em, -9.36em) scale(1.39); } + 100% { opacity: 0; transform: translate(-1.09em, -10.00em) scale(0); } + } + @keyframes flutter1 { + 0% { opacity: 0.9; transform: translate( 0.00em, 0.00em) scale(1.00); } + 10% { opacity: 0.9; transform: translate(-0.15em, -1.64em) scale(1.46); } + 20% { opacity: 0.9; transform: translate(-0.38em, -3.16em) scale(1.55); } + 30% { opacity: 0.9; transform: translate(-0.17em, -4.56em) scale(1.09); } + 40% { opacity: 0.9; transform: translate( 0.53em, -5.84em) scale(0.47); } + 50% { opacity: 0.9; transform: translate( 0.99em, -7.00em) scale(0.28); } + 60% { opacity: 0.9; transform: translate( 0.49em, -8.04em) scale(0.78); } + 70% { opacity: 0.9; transform: translate(-0.76em, -8.96em) scale(1.56); } + 80% { opacity: 0.9; transform: translate(-1.60em, -9.76em) scale(1.89); } + 90% { opacity: 0.6; transform: translate(-0.97em, -10.44em) scale(1.39); } + 100% { opacity: 0; transform: translate( 0.84em, -11.00em) scale(0); } + } + @keyframes flutter2 { + 0% { opacity: 0.9; transform: translate( 0.00em, -0.00em) scale(1.00); } + 10% { opacity: 0.9; transform: translate( 0.13em, -1.17em) scale(1.46); } + 20% { opacity: 0.9; transform: translate( 0.40em, -2.28em) scale(1.55); } + 30% { opacity: 0.9; transform: translate( 0.25em, -3.33em) scale(1.09); } + 40% { opacity: 0.9; transform: translate(-0.44em, -4.32em) scale(0.47); } + 50% { opacity: 0.9; transform: translate(-1.00em, -5.25em) scale(0.28); } + 60% { opacity: 0.9; transform: translate(-0.64em, -6.12em) scale(0.78); } + 70% { opacity: 0.9; transform: translate( 0.59em, -6.93em) scale(1.56); } + 80% { opacity: 0.9; transform: translate( 1.58em, -7.68em) scale(1.89); } + 90% { opacity: 0.6; transform: translate( 1.17em, -8.37em) scale(1.39); } + 100% { opacity: 0; transform: translate(-0.58em, -9.00em) scale(0); } + } + #level { + font-size: 1.5rem; + font-family: monospace; + color: pink; + text-align: center; + } + </style> + </head> + <body> + <h1 id="level"></h1> + <div id="main"></div> + <div id="hearts"></div> + <script src="hug.js"></script> + </body> +</html> \ No newline at end of file