diff options
author | Florrie <towerofnix@gmail.com> | 2019-01-16 14:37:45 -0400 |
---|---|---|
committer | Florrie <towerofnix@gmail.com> | 2019-01-16 14:37:45 -0400 |
commit | b3a6398b03839d9a9c5f2a1a9bac144867e283a6 (patch) | |
tree | 012b8673f319efa1b5789bbc0fcaa4b986614799 |
Initial commit
-rw-r--r-- | .editorconfig | 9 | ||||
-rw-r--r-- | data.js | 153 | ||||
-rw-r--r-- | faces/common/al.png | bin | 0 -> 487 bytes | |||
-rw-r--r-- | faces/common/asg.png | bin | 0 -> 737 bytes | |||
-rw-r--r-- | faces/common/pap.png | bin | 0 -> 336 bytes | |||
-rw-r--r-- | faces/common/sans.png | bin | 0 -> 377 bytes | |||
-rw-r--r-- | faces/common/tor.png | bin | 0 -> 397 bytes | |||
-rw-r--r-- | faces/common/und.png | bin | 0 -> 453 bytes | |||
-rw-r--r-- | faces/deltarune/ber.png | bin | 0 -> 499 bytes | |||
-rw-r--r-- | faces/deltarune/jok.png | bin | 0 -> 618 bytes | |||
-rw-r--r-- | faces/deltarune/lan.png | bin | 0 -> 714 bytes | |||
-rw-r--r-- | faces/deltarune/noe.png | bin | 0 -> 886 bytes | |||
-rw-r--r-- | faces/deltarune/ral.png | bin | 0 -> 886 bytes | |||
-rw-r--r-- | faces/deltarune/rud.png | bin | 0 -> 760 bytes | |||
-rw-r--r-- | faces/deltarune/sus.png | bin | 0 -> 622 bytes | |||
-rw-r--r-- | fonts/DTM-Mono.otf | bin | 0 -> 24412 bytes | |||
-rw-r--r-- | index.html | 46 | ||||
-rw-r--r-- | main.js | 419 | ||||
-rw-r--r-- | sounds/common/al.wav | bin | 0 -> 4878 bytes | |||
-rw-r--r-- | sounds/common/asg.wav | bin | 0 -> 16580 bytes | |||
-rw-r--r-- | sounds/common/pap.wav | bin | 0 -> 17368 bytes | |||
-rw-r--r-- | sounds/common/sans.wav | bin | 0 -> 24948 bytes | |||
-rw-r--r-- | sounds/common/tor.wav | bin | 0 -> 14220 bytes | |||
-rw-r--r-- | sounds/common/und.wav | bin | 0 -> 11564 bytes | |||
-rw-r--r-- | sounds/deltarune/ber.wav | bin | 0 -> 16188 bytes | |||
-rw-r--r-- | sounds/deltarune/echo.wav | bin | 0 -> 88638 bytes | |||
-rw-r--r-- | sounds/deltarune/jok.wav | bin | 0 -> 4258 bytes | |||
-rw-r--r-- | sounds/deltarune/lan.wav | bin | 0 -> 4360 bytes | |||
-rw-r--r-- | sounds/deltarune/noe.wav | bin | 0 -> 3862 bytes | |||
-rw-r--r-- | sounds/deltarune/ral.wav | bin | 0 -> 12250 bytes | |||
-rw-r--r-- | sounds/deltarune/rud.wav | bin | 0 -> 3310 bytes | |||
-rw-r--r-- | sounds/deltarune/sus.wav | bin | 0 -> 11464 bytes | |||
-rw-r--r-- | style.css | 223 |
33 files changed, 850 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e73c4f9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_size = 4 +indent_style = space +trim_trailing_whitespace = true diff --git a/data.js b/data.js new file mode 100644 index 0000000..e6f4c77 --- /dev/null +++ b/data.js @@ -0,0 +1,153 @@ +/** + * + * hi this is the data for the game + * + */ + +'use strict'; + +window.gameData = { + characters: [ + { + name: 'Alphys', + games: ['undertale', 'deltarune'], + file: 'al', + volume: 1.0, speed: 50, // TODO: I don't think Alphys is physically capable of speaking up + messages: [ + `Watching someone on\na screen really makes\nyou root for them.`, + `S-so, ahhh, now I\nwant to help you!`, + `Using my knowledge,\nI can easily guide\nyou through Hotland!` + ] + }, + { + name: 'Asgore', + games: ['undertale', 'deltarune'], + file: 'asg', + volume: 0.5, speed: 80, + messages: [ + `Oh?\nIs someone there?`, + `Would you like\na cup of tea?` + ] + }, + { + name: 'Berdly', + games: ['deltarune'], + file: 'ber', + volume: 0.5, speed: 50, + messages: [ + `Sorry, I'm already\npartners with the 2nd\nsmartest student.`, + `Your unique skillset\nmight help a LOT on this\nassignment!`, + `We're FINE being alone!` + ] + }, + { + name: 'Jevil', + games: ['deltarune'], + file: 'jok', + volume: 0.5, speed: 50, + messages: [ + `UEE HEE HEE, THE KEY, THE KEY.`, + `A MARVELOUS FUN IS ABOUT TO\nBREAK FREE.`, + `WHEN YOUR HP DROPS TO 0, YOU LOSE!` + ] + }, + { + name: 'Lancer', + games: ['deltarune'], + file: 'lan', + volume: 0.5, speed: 50, + messages: [ + `You're going to be\nthrashed!`, + `AHHHHH HA HA HA HA HA HA\nHA HA!!!!`, + `Merry Christmas!` + ] + }, + { + name: 'Noelle', + games: ['deltarune'], + file: 'noe', + volume: 0.5, speed: 40, + messages: [ + `I could ask Ms. Alphys\nif we could make\na group of 3!`, + `B-but if I die, you're\npaying for my funeral, Kris!`, + `(Though, honestly, if\nshe's nice I might die, too...)` + ] + }, + { + name: 'Papyrus', + games: ['undertale', 'deltarune'], + file: 'pap', + volume: 0.4, speed: 50, + messages: [ + `I GUESS\nI CAN MAKE AN\nALLOWANCE FOR YOU!`, + `WOW!!!\nI HAVE FRIENDS!!!`, + `YOU TAUGHT ME A\nLOT, HUMAN.` + ] + }, + { + name: 'Ralsei', + games: ['deltarune'], + file: 'ral', + volume: 0.5, speed: 50, + messages: [ + `I hope we can be good\nfriends, Kris.`, + `It'll fall asleep, and we'll win peacefully!`, + `As heroes, we have the\npower to make a peaceful\nfuture!` + ] + }, + { + name: 'Rudy', + games: ['deltarune'], + file: 'rud', + volume: 0.5, speed: 50, + messages: [ + `Well jingle my goshdarn\nbells! Looks like\nKrismas came early!`, + `Don't worry, there's no\nway you can bore me\nright now!`, + `Yikes, man!` + ] + }, + { + name: 'Sans', + games: ['undertale', 'deltarune'], + file: 'sans', + volume: 0.4, speed: 50, + messages: [ + `anyways,\nyou're a human, right?`, + `i dont really care about\ncapturing anybody.`, + `staring at this lamp.\nits really cool.` + ] + }, + { + name: 'Susie', + games: ['deltarune'], + file: 'sus', + volume: 0.5, speed: 50, + messages: [ + `God, can you walk any\nslower, or what?`, + `Oh, you're not dead.\nSweet.`, + `Why don't we just climb\nover this spiked fence?` + ] + }, + { + name: 'Toriel', + games: ['undertale', 'deltarune'], + file: 'tor', + volume: 0.5, speed: 50, + messages: [ + `You have done\nexcellently thus\nfar, my child.`, + `Thank you for trusting\nme.`, + `If you have a need for\nanything, just call.` + ] + }, + { + name: 'Undyne', + games: ['undertale', 'deltarune'], + file: 'und', + messages: [ + `Homemade noodles\nare the best!`, + `BUT I JUST BUY\nSTORE-BRAND!`, + `NGAHHHHHHHHH\nHHHHHHHHHH!!!` + ] + } + ] +}; diff --git a/faces/common/al.png b/faces/common/al.png new file mode 100644 index 0000000..9c751ba --- /dev/null +++ b/faces/common/al.png Binary files differdiff --git a/faces/common/asg.png b/faces/common/asg.png new file mode 100644 index 0000000..1fb230d --- /dev/null +++ b/faces/common/asg.png Binary files differdiff --git a/faces/common/pap.png b/faces/common/pap.png new file mode 100644 index 0000000..98779a4 --- /dev/null +++ b/faces/common/pap.png Binary files differdiff --git a/faces/common/sans.png b/faces/common/sans.png new file mode 100644 index 0000000..c29854e --- /dev/null +++ b/faces/common/sans.png Binary files differdiff --git a/faces/common/tor.png b/faces/common/tor.png new file mode 100644 index 0000000..3408f37 --- /dev/null +++ b/faces/common/tor.png Binary files differdiff --git a/faces/common/und.png b/faces/common/und.png new file mode 100644 index 0000000..0b33165 --- /dev/null +++ b/faces/common/und.png Binary files differdiff --git a/faces/deltarune/ber.png b/faces/deltarune/ber.png new file mode 100644 index 0000000..b4692bf --- /dev/null +++ b/faces/deltarune/ber.png Binary files differdiff --git a/faces/deltarune/jok.png b/faces/deltarune/jok.png new file mode 100644 index 0000000..948d353 --- /dev/null +++ b/faces/deltarune/jok.png Binary files differdiff --git a/faces/deltarune/lan.png b/faces/deltarune/lan.png new file mode 100644 index 0000000..dbcbb2c --- /dev/null +++ b/faces/deltarune/lan.png Binary files differdiff --git a/faces/deltarune/noe.png b/faces/deltarune/noe.png new file mode 100644 index 0000000..a775b55 --- /dev/null +++ b/faces/deltarune/noe.png Binary files differdiff --git a/faces/deltarune/ral.png b/faces/deltarune/ral.png new file mode 100644 index 0000000..98cd9a8 --- /dev/null +++ b/faces/deltarune/ral.png Binary files differdiff --git a/faces/deltarune/rud.png b/faces/deltarune/rud.png new file mode 100644 index 0000000..654c612 --- /dev/null +++ b/faces/deltarune/rud.png Binary files differdiff --git a/faces/deltarune/sus.png b/faces/deltarune/sus.png new file mode 100644 index 0000000..5c42624 --- /dev/null +++ b/faces/deltarune/sus.png Binary files differdiff --git a/fonts/DTM-Mono.otf b/fonts/DTM-Mono.otf new file mode 100644 index 0000000..4135289 --- /dev/null +++ b/fonts/DTM-Mono.otf Binary files differdiff --git a/index.html b/index.html new file mode 100644 index 0000000..bd0759c --- /dev/null +++ b/index.html @@ -0,0 +1,46 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>guess the character</title> + <link rel="stylesheet" href="style.css"> + </head> + <body> + <canvas id="canvas"></canvas> + <div id="everything-lol"> + <noscript> + <p>* Like, enable JavaScript.</p> + </noscript> + <div id="js-not-working"> + <p>Uh, this is awkward. The JavaScript code isn't working.</p> + <p>Maybe it isn't loaded in yet? Just give it a minute, if your browser says the page is still loading...</p> + <p>Otherwise, your browser might be kinda old. Try a recent version of Firefox or Chrome or something like that.</p> + <p>Or like, who knows. Maybe I broke the code and it just doesn't work anymore.</p> + </div> + <div id="crashed"> + <p>Oh heck this is the worst thing possible. <span class="red">The game crashed.</span></p> + <p>Sorry!!! Here is the error. Please share this with the game author on, like, The Internet.</p> + <pre id="crash-trace"></pre> + </div> + <div id="container"> + <h1>GUESS THE CHARACTER</h1> + <div id="intro"> + <p>is a game in which you GUESS THE CHARACTER based on the sound of their speech.</p> + <p>Loading (<span id="load-progress">0</span>%)...</p> + <p><a href="#" id="play-link">Play</a></p> + </div> + </div> + <div id="game"> + <div id="choice-container"></div> + <div id="results" class="hide"> + <p id="correct"><span>Correct!</span></p> + <p id="incorrect"><span>Incorrect.</span><br>The correct choice was <span id="correct-character">Noelle</span>.</p> + <p><a href="#" id="next-link">Next</a></p> + </div> + <div id="scorekeeper"></div> + </div> + </div> + <script src="data.js"></script> + <script src="main.js"></script> + </body> +</html> diff --git a/main.js b/main.js new file mode 100644 index 0000000..97966f5 --- /dev/null +++ b/main.js @@ -0,0 +1,419 @@ +/** + * + * IDEAS LOL + * + * - make the game, dummy + * + * - hide the image, or the name -- i.e. force the user to guess based on one + * or the other, not both + * + * - pick __ HARD __ selections of choices, not just totally random ones + * + */ + +// initializy stuff --------------------------------------------------------ooo + +'use strict'; + +// sorry this is cursed +const { gameData } = window; + +document.body.classList.add('js-enabled'); + +// resource loading --------------------------------------------------------o.o + +const resources = { + imageMap: new Map(), + soundMap: new Map() +}; + +let loadTotal = 0; +let loadSoFar = 0; + +function loadResources() { + // 2 assets for each character: image, sound. + loadTotal = gameData.characters.length * 2; + + return Promise.all([ + loadImages(), + loadSounds() + ]); +} + +async function loadImages() { + for (const character of gameData.characters) { + const image = new Image(); + resources.imageMap.set(character, image); + + const path = `faces/${getCharacterPath(character)}.png`; + image.src = path; + + await new Promise((resolve, reject) => { + image.addEventListener('load', () => resolve()); + + image.addEventListener('error', () => { + reject(new Error('Failed to load image from path ' + path)); + }); + }); + + loadSoFar++; + updateLoadProgress(); + } +} + +async function loadSounds() { + for (const character of gameData.characters) { + const audio = new Audio(); + resources.soundMap.set(character, audio); + + const path = `sounds/${getCharacterPath(character)}.wav`; + audio.src = path; + + await new Promise((resolve, reject) => { + audio.addEventListener('canplaythrough', () => resolve()); + + audio.addEventListener('error', () => { + reject(new Error('Failed to load audio from path ' + path)); + }); + }); + + loadSoFar++; + updateLoadProgress(); + } +} + +function updateLoadProgress() { + const el = document.getElementById('load-progress'); + if (loadSoFar < loadTotal) { + el.innerHTML = Math.floor(loadSoFar / loadTotal * 100); + } else { + el.parentElement.innerHTML = 'Loaded!'; + } +} + +function getCharacterPath(character) { + let path = ''; + if (character.games.length >= 2) { + path += 'common/'; + } else if (character.games.length === 1) { + path += character.games[0] + '/'; + } else { + // uhhhh what + throw new error(character.name + " isn't actually part of any games??"); + } + path += character.file; + return path; +} + +// talky talky -------------------------------------------------------------oWo + +function wrapMessage(msg, length = 23) { + // so h*ck, apparently word wrapping is Not Automatic in undertale + // best we just specify word-wraps in the unmodified message text. + // keeping this function around just in case though. + const words = msg.split(' '); + const lines = [[]]; + let col = 0; + for (let i = 0; i < words.length; i++) { + const word = words[i]; + col += word.length + 1; + if (col > length) { + lines.push([word]); + col = 0; + } else { + lines[lines.length - 1].push(word); + } + } + return lines.map(l => l.join(' ')).join('\n'); +} + +const audioCtx = new AudioContext(); +const analyser = audioCtx.createAnalyser(); +analyser.fftSize = 256; +analyser.connect(audioCtx.destination); + +async function doSpeech(character, msg) { + const audio = resources.soundMap.get(character); + if (!audio) { + return; + } + + for (let i = 0; i < msg.length; i++) { + const char = msg[i]; + // Yeah all these timings are wrong but they're decent estimations. + if (char === ',' || char === '.') { + await delay(300); + while (msg[i + 1] === ',') i++; // Deal with ellipsis + } else if (char === '\n') { + await delay(80); + } else if (char === ' ') { + await delay(30); + } else { + const a = audio.cloneNode(); + a.volume = character.volume || 0.5; + + const source = audioCtx.createMediaElementSource(a); + source.connect(analyser); + + a.play(); + await delay(character.speed || 50); + } + } +} + +const canvas = document.getElementById('canvas'); +const streamData = new Uint8Array(128); + +function sampleAudioStream() { + analyser.getByteFrequencyData(streamData); + + const rect = document.body.getBoundingClientRect(); + canvas.width = rect.width; + canvas.height = rect.height; + const ctx = canvas.getContext('2d'); + ctx.clearRect(0, 0, canvas.width, canvas.height); + + let lastTop = null; + for (let i = 0; i < 60; i++) { // i < N is arbitrary, this value seems pretty good for most voices + const w = canvas.width / 60; + const x = w * i; + const h = (0.9 * canvas.height / 255) * streamData[i]; + ctx.fillStyle = 'white'; + + const top = h / 2; + if (lastTop) ctx.fillRect(x, canvas.height / 2 + top, 1, lastTop - top); + ctx.fillRect(x, canvas.height / 2 + top, w, 2); + if (lastTop) ctx.fillRect(x, canvas.height / 2 - top, 1, top - lastTop); + ctx.fillRect(x, canvas.height / 2 - top, w, 2); + lastTop = top; + } + + requestAnimationFrame(sampleAudioStream); +} + +requestAnimationFrame(sampleAudioStream); + +// display choices ---------------------------------------------------------www + +function displayChoices(characters, confirmCharacterCb) { + return new Promise(async resolve => { + const container = document.getElementById('choice-container'); + while (container.firstChild) { + container.removeChild(container.firstChild); + } + container.classList.remove('hide'); + + let selected = false; + for (const character of characters) { + const el = document.createElement('a'); + el.href = '#'; + el.classList.add('character-choice'); + el.appendChild(resources.imageMap.get(character)); + const span = document.createElement('span'); + span.appendChild(document.createTextNode(character.name)); + el.appendChild(span); + container.appendChild(el); + + el.addEventListener('click', () => { + if (!selected) { + selected = true; + resolve(character); + } + }); + } + + container.children[0].focus(); + for (const el of container.children) { + el.classList.add('visible'); + await delay(800 / container.children.length); + } + }); +} + +// utilitylol --------------------------------------------------------------uwu + +function characterWithName(name) { + return gameData.characters.find(chr => chr.name === name); +} + +function pickRandom(array) { + return array[Math.floor(Math.random() * array.length)]; +} + +function spliceRandom(array) { + const val = pickRandom(array); + array.splice(array.indexOf(val), 1); + return val; +} + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +function waitForEvent(el, eventName) { + return new Promise(resolve => { + el.addEventListener(eventName, function cb(evt) { + el.removeEventListener(eventName, cb); + resolve(evt); + }); // if only {once: true} were "more supported" + // as if that' s something I care about in this game + }); +} + +// scorekeeper -------------------------------------------------------------*** + +function setupScorekeeper(numCharacters) { + const container = document.getElementById('scorekeeper'); + for (let i = 0; i < numCharacters; i++) { + const el = document.createElement('div') + el.classList.add('marker'); + el.classList.add('unset'); + container.appendChild(el); + } +} + +function markScorekeeper(cls, character) { + const el = scorekeeper.querySelector('.unset'); + el.classList.remove('unset'); + el.classList.add(cls); + el.appendChild(resources.imageMap.get(character).cloneNode()); + el.title = character.name +} + +// uh start it now ---------------------------------------------------------aA! + +async function mainLol() { + const testChar = 'Noellef'; + + await loadResources(); + + document.body.addEventListener('keydown', evt => { + const choiceContainer = document.getElementById('choice-container'); + if (!choiceContainer.classList.contains('hide')) { + if (/^[0-9]$/.test(evt.key)) { + const el = choiceContainer.children[evt.key - 1]; + if (document.activeElement === el) { + el.click(); + } else if (el) { + el.focus(); + } + } else if (event.key === 'ArrowRight') { + const el = document.activeElement; + if (el.parentElement === choiceContainer && el.nextSibling) { + el.nextSibling.focus(); + } + } else if (event.key === 'ArrowLeft') { + const el = document.activeElement; + if (el.parentElement === choiceContainer && el.previousSibling) { + el.previousSibling.focus(); + } + } + } + + if (event.which === 90) { // Z + if (document.activeElement.click) { + document.activeElement.click(); + } + } + }); + + const gameEl = document.getElementById('game'); + + const playLink = document.getElementById('play-link'); + playLink.focus(); + await waitForEvent(playLink, 'click'); + + document.body.classList.add('game'); + + const deckGames = ['deltarune']; + const hardMode = false; + + const characterDeck = gameData.characters.filter(chr => chr.games.some(g => deckGames.includes(g))); + + setupScorekeeper(characterDeck.length); + + while (characterDeck.length) { + gameEl.classList.remove('correct'); + gameEl.classList.remove('incorrect'); + + const correctCharacter = characterWithName(testChar) || spliceRandom(characterDeck); + + const numChoices = 6; + const potentialOptions = characterDeck.slice().filter(chr => chr !== correctCharacter); + const correctIndex = Math.min(Math.floor(Math.random() * numChoices), potentialOptions.length); + const allCharacters = []; + for (let i = 0; i < numChoices; i++) { + if (i === correctIndex) { + allCharacters.push(correctCharacter); + } else if (potentialOptions.length) { + let choice; + allCharacters.push(spliceRandom(potentialOptions)); + } else { + break + } + } + + let msg; + if (hardMode) { + msg = pickRandom(['Oh?', 'Hello!']); + } else { + msg = pickRandom(correctCharacter.messages); + } + + await doSpeech(correctCharacter, msg); + await delay(500); + + const choice = await displayChoices(allCharacters); + + const container = document.getElementById('choice-container'); + for (let i = 0; i < allCharacters.length; i++) { + const el = container.children[i]; + if (i === correctIndex) { + el.classList.add('correct'); + } else { + el.classList.add('incorrect'); + } + if (i === allCharacters.indexOf(choice)) { + el.classList.add('chosen'); + } else { + el.classList.add('not-chosen'); + } + } + + if (choice === correctCharacter) { + markScorekeeper('correct', correctCharacter); + } else { + markScorekeeper('incorrect', correctCharacter); + } + + await delay(200); + + if (choice === correctCharacter) { + gameEl.classList.add('correct'); + } else { + gameEl.classList.add('incorrect'); + const el = document.getElementById('correct-character'); + el.innerHTML = ''; + el.appendChild(document.createTextNode(correctCharacter.name)); + } + + document.getElementById('results').classList.remove('hide'); + + const nextLink = document.getElementById('next-link'); + nextLink.focus(); + await waitForEvent(nextLink, 'click'); + + document.getElementById('choice-container').classList.add('hide'); + document.getElementById('results').classList.add('hide'); + + await delay(400); + } +} + +mainLol().catch(error => { + document.body.classList.add('crashed'); + document.getElementById('crash-trace').appendChild(document.createTextNode( + error.message + '\n' + + error.stack + )); +}); diff --git a/sounds/common/al.wav b/sounds/common/al.wav new file mode 100644 index 0000000..e99a61f --- /dev/null +++ b/sounds/common/al.wav Binary files differdiff --git a/sounds/common/asg.wav b/sounds/common/asg.wav new file mode 100644 index 0000000..eba4a26 --- /dev/null +++ b/sounds/common/asg.wav Binary files differdiff --git a/sounds/common/pap.wav b/sounds/common/pap.wav new file mode 100644 index 0000000..d015d82 --- /dev/null +++ b/sounds/common/pap.wav Binary files differdiff --git a/sounds/common/sans.wav b/sounds/common/sans.wav new file mode 100644 index 0000000..06cd4d7 --- /dev/null +++ b/sounds/common/sans.wav Binary files differdiff --git a/sounds/common/tor.wav b/sounds/common/tor.wav new file mode 100644 index 0000000..65a735c --- /dev/null +++ b/sounds/common/tor.wav Binary files differdiff --git a/sounds/common/und.wav b/sounds/common/und.wav new file mode 100644 index 0000000..f4eb7f7 --- /dev/null +++ b/sounds/common/und.wav Binary files differdiff --git a/sounds/deltarune/ber.wav b/sounds/deltarune/ber.wav new file mode 100644 index 0000000..a0e7049 --- /dev/null +++ b/sounds/deltarune/ber.wav Binary files differdiff --git a/sounds/deltarune/echo.wav b/sounds/deltarune/echo.wav new file mode 100644 index 0000000..e751310 --- /dev/null +++ b/sounds/deltarune/echo.wav Binary files differdiff --git a/sounds/deltarune/jok.wav b/sounds/deltarune/jok.wav new file mode 100644 index 0000000..5049c16 --- /dev/null +++ b/sounds/deltarune/jok.wav Binary files differdiff --git a/sounds/deltarune/lan.wav b/sounds/deltarune/lan.wav new file mode 100644 index 0000000..0fbc700 --- /dev/null +++ b/sounds/deltarune/lan.wav Binary files differdiff --git a/sounds/deltarune/noe.wav b/sounds/deltarune/noe.wav new file mode 100644 index 0000000..aa9350f --- /dev/null +++ b/sounds/deltarune/noe.wav Binary files differdiff --git a/sounds/deltarune/ral.wav b/sounds/deltarune/ral.wav new file mode 100644 index 0000000..39b76a1 --- /dev/null +++ b/sounds/deltarune/ral.wav Binary files differdiff --git a/sounds/deltarune/rud.wav b/sounds/deltarune/rud.wav new file mode 100644 index 0000000..1daab6f --- /dev/null +++ b/sounds/deltarune/rud.wav Binary files differdiff --git a/sounds/deltarune/sus.wav b/sounds/deltarune/sus.wav new file mode 100644 index 0000000..8e106f0 --- /dev/null +++ b/sounds/deltarune/sus.wav Binary files differdiff --git a/style.css b/style.css new file mode 100644 index 0000000..1c2a35d --- /dev/null +++ b/style.css @@ -0,0 +1,223 @@ +@font-face { + font-family: DTM-Mono; + src: url("fonts/DTM-Mono.otf") format("opentype"); +} + +canvas { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: -1; +} + +#everything-lol { + height: 400px; + border: 1px dotted #222; + padding: 20px; + background: rgba(0, 0, 0, 0.8); + box-shadow: 0 0 32px black; + position: relative; +} + +body:not(.js-enabled) #container { + display: none; +} + +#js-not-working { + text-align: start; +} + +body.js-enabled #js-not-working { + display: none !important; +} + +body:not(.crashed) #crashed { + display: none; +} + +body.game #intro { + display: none; +} + +#crash-trace { + text-align: start; + border: 1pt dotted white; + padding: 4pt; +} + +#choice-container { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + position: relative; + top: 0; +} + +#choice-container.hide, #results.hide { + top: 10px; + opacity: 0; + transition: top 0.5s, opacity 0.5s; +} + +#results { + transition: opacity 0.5s; +} + +.character-choice { + color: white; + display: flex; + flex-direction: column; + align-items: center; + padding: 15px; + margin: 5px; + position: relative; + cursor: pointer; + border: 2px solid transparent; +} + +.character-choice img { + margin-bottom: 5px; + background-color: black; +} + +.character-choice:focus { + outline: 1px dotted yellow; +} + +.character-choice:not(.visible) { + opacity: 0; + bottom: 10px; +} + +.character-choice.visible { + opacity: 1; + bottom: 0; + transition: opacity 0.5s, bottom 0.5s, color 0.2s; +} + +.character-choice { + --my-color: white; + color: var(--my-color); +} + +.character-choice.correct { + --my-color: green; +} + +.character-choice.incorrect { + --my-color: red; +} + +.character-choice.chosen { + border-color: var(--my-color); + bottom: 5px; +} + +.character-choice.not-chosen { + bottom: -5px; + opacity: 0.6; +} + +.character-choice.correct.not-chosen { + border: 2px dashed var(--my-color); +} + +#game:not(.correct) #correct { + display: none; +} + +#game:not(.incorrect) #incorrect { + display: none; +} + +#correct span { + color: green; +} + +#incorrect span:first-child { + color: red; +} + +#incorrect span:last-child { + color: green; +} + +#scorekeeper { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 30px; + display: flex; +} + +#scorekeeper .marker { + flex-basis: 0; + flex-grow: 1; + height: 100%; + opacity: 0.5; + border-top: 1px solid rgba(255, 255, 255, 0.5); + transition: background-color 0.5s; +} + +#scorekeeper .marker:not(:last-child) { + border-right: 1px solid rgba(255, 255, 255, 0.5); +} + +#scorekeeper .marker img { + object-fit: contain; + height: calc(100% - 4px); + margin-top: 2px; + background: black; +} + +#scorekeeper .marker.unset { + background-color: #111; +} + +#scorekeeper .marker.correct { + background-color: green; +} + +#scorekeeper .marker.incorrect { + background-color: red; +} + +body, html { + width: 100%; + height: 100%; + padding: 0; + margin: 0; +} + +body { + background-color: #080808; + color: white; + font-family: DTM-Mono; + text-align: center; + + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + padding: 10px; + box-sizing: border-box; +} + +h1 { + letter-spacing: 1pt; +} + +p { + width: 40em; +} + +a { + color: yellow; + text-decoration: none; + border-bottom: 1px dotted yellow; +} |