diff options
Diffstat (limited to 'public')
| -rw-r--r-- | public/about.html | 42 | ||||
| -rw-r--r-- | public/audio/western-cover.mp3 | bin | 0 -> 435945 bytes | |||
| -rw-r--r-- | public/dragons.js | 222 | ||||
| -rw-r--r-- | public/fonts/gameofthrones.ttf | bin | 0 -> 28784 bytes | |||
| -rw-r--r-- | public/images/dragon-sizes.png | bin | 0 -> 374143 bytes | |||
| -rw-r--r-- | public/images/hat-texas.gif | bin | 0 -> 161381 bytes | |||
| -rw-r--r-- | public/images/pixel-lasso.jpeg | bin | 0 -> 23529 bytes | |||
| -rw-r--r-- | public/index.html | 163 | ||||
| -rw-r--r-- | public/style.css | 88 |
9 files changed, 515 insertions, 0 deletions
diff --git a/public/about.html b/public/about.html new file mode 100644 index 0000000..138d1e9 --- /dev/null +++ b/public/about.html @@ -0,0 +1,42 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Name my Dragon - About</title> + <link rel="stylesheet" href="style.css"> +</head> +<body> + <center> + <h1>How it works</h1> + <div class="container"> + <img class="flex" src="images/pixel-lasso.jpeg" max-width="50%" alt="Pixel art of a cowboy lassoing a dragon."> + <div class="flex flex2" style="max-width: 500px; color: unset;"> + <p> + This site uses word similarity to score all dragon names from George R.R. Martin's + <a href="https://en.wikipedia.org/wiki/Game_of_Thrones" target="_blank">A Song of Ice and Fire</a> + universe in terms of their "closeness" to the given name. + The dragon name that is the "closest" is the one selected as the user's dragon. + </p> + <p> + It uses three popular techniques in + <a href="https://en.wikipedia.org/wiki/Natural_language_processing" target="_blank">NLP</a> + to calculate similarity scores - these are the + <a href="https://en.wikipedia.org/wiki/Levenshtein_distance" target="_blank">Levenshtein Distance</a>, + <a href="https://en.wikipedia.org/wiki/Cosine_similarity" target="_blank">Cosine Similarity</a>, + and <a href="https://en.wikipedia.org/wiki/Jaccard_index" target="_blank">Jaccard Similarity</a>. + </p> + <p> + The final result shown to the user uses cosine similarity only, + but top ranking dragons from each of the other two techniques are + also shown as alternatives. + </p> + </div> + </div> + <footer> + <a href="index.html">Home</a><br> + <a href="https://kumardamani.net" target="_blank">Author</a> + </footer> + </center> +</body> +</html> diff --git a/public/audio/western-cover.mp3 b/public/audio/western-cover.mp3 Binary files differnew file mode 100644 index 0000000..c735513 --- /dev/null +++ b/public/audio/western-cover.mp3 diff --git a/public/dragons.js b/public/dragons.js new file mode 100644 index 0000000..5dd3ecb --- /dev/null +++ b/public/dragons.js @@ -0,0 +1,222 @@ +const dragons = [ + { + name: "Drogon", + description: "The largest and most aggressive of Daenerys' dragons. Black with red markings.", + rider: "Daenerys Targaryen", + imageId: "drogon", + size: "Very large, wingspan over 100 feet by adulthood", + primaryColor: "#000000", + secondaryColor: "#8B0000", + age: "About 7 years by end of series", + notableAbilities: ["Extremely hot flame", "Largest of Daenerys' dragons"] + }, + { + name: "Rhaegal", + description: "Green-scaled with bronze accents. Named after Daenerys' brother Rhaegar.", + rider: "Daenerys Targaryen", + imageId: "rhaegal", + size: "Large, smaller than Drogon", + primaryColor: "#008000", + secondaryColor: "#704214", + age: "About 7 years by end of series", + notableAbilities: ["Agile flyer"] + }, + { + name: "Viserion", + description: "Cream and gold colored. Named after Daenerys' brother Viserys.", + rider: "Daenerys Targaryen", + imageId: "viserion", + size: "Large, similar to Rhaegal", + primaryColor: "#FFFDD0", + secondaryColor: "#B8860B", + age: "About 7 years by end of series", + notableAbilities: ["Ice breath (after death and reanimation)"] + }, + { + name: "Balerion the Black Dread", + description: "The largest known dragon, black-scaled.", + rider: "Aegon the Conqueror", + imageId: "balerion", + size: "Immense, could swallow a mammoth whole", + primaryColor: "#000000", + secondaryColor: "#2F4F4F", + age: "Approximately 200 years at time of death", + notableAbilities: ["Extremely hot flame", "Largest known dragon"] + }, + { + name: "Vhagar", + description: "One of the three dragons used in the conquest of Westeros. Bronze with greenish-blue highlights.", + rider: "Visenya Targaryen", + imageId: "vhagar", + size: "Nearly as large as Balerion in old age", + primaryColor: "#CD7F32", + secondaryColor: "#2F4F4F", + age: "Approximately 181 years at time of death", + notableAbilities: ["One of the largest dragons", "Veteran of many battles"] + }, + { + name: "Meraxes", + description: "Silver-scaled dragon ridden by Rhaenys Targaryen during the conquest.", + rider: "Rhaenys Targaryen", + imageId: "meraxes", + size: "Large, but smaller than Balerion", + primaryColor: "#C0C0C0", + secondaryColor: "#4B0082", + age: "Unknown", + notableAbilities: ["One of the dragons of Aegon's Conquest"] + }, + { + name: "Caraxes", + description: "Known as the Blood Wyrm, red-scaled and fierce.", + rider: "Daemon Targaryen", + imageId: "caraxes", + size: "Large", + primaryColor: "#FF0000", + secondaryColor: "#8B0000", + age: "Unknown", + notableAbilities: ["Fierce in battle", "Formidable fighter"] + }, + { + name: "Syrax", + description: "Yellow-scaled dragon ridden by Rhaenyra Targaryen.", + rider: "Rhaenyra Targaryen", + imageId: "syrax", + size: "Medium to large", + primaryColor: "#FFFF00", + secondaryColor: "#8B4513", + age: "Unknown", + notableAbilities: ["Swift flyer"] + }, + { + name: "Meleys", + description: "Called the Red Queen, red-scaled with pink wings.", + rider: "Rhaenys Targaryen (the Queen Who Never Was)", + imageId: "meleys", + size: "Large", + primaryColor: "#FF0000", + secondaryColor: "#8B008B", + age: "Unknown", + notableAbilities: ["Swift and fearsome in battle"] + }, + { + name: "Sunfyre", + description: "Described as the most beautiful dragon, with golden scales and pink wing membranes.", + rider: "Aegon II Targaryen", + imageId: "sunfyre", + size: "Medium to large", + primaryColor: "#FFD700", + secondaryColor: "#8B4513", + age: "Young adult during the Dance of the Dragons", + notableAbilities: ["Exceptional beauty", "Formidable in combat"] + }, + { + name: "Vermithor", + description: "Bronze-scaled with tan wings. One of the larger dragons.", + rider: "King Jaehaerys I Targaryen", + imageId: "vermithor", + size: "Very large, third largest after Balerion and Vhagar", + primaryColor: "#CD7F32", + secondaryColor: "#8B4513", + age: "Approximately 100 years during the Dance of the Dragons", + notableAbilities: ["Extremely large and powerful"] + }, + { + name: "Silverwing", + description: "Silver-scaled dragon, often paired with Vermithor.", + rider: "Queen Alysanne Targaryen", + imageId: "silverwing", + size: "Large", + primaryColor: "#C0C0C0", + secondaryColor: "#4B0082", + age: "Approximately 80-90 years during the Dance of the Dragons", + notableAbilities: ["Gentle temperament"] + }, + { + name: "Dreamfyre", + description: "Slender, pale blue dragon with silver markings.", + rider: "Helaena Targaryen", + imageId: "dreamfyre", + size: "Medium", + primaryColor: "#ADD8E6", + secondaryColor: "#4169E1", + age: "Unknown", + notableAbilities: ["Agile flyer"] + }, + { + name: "Tessarion", + description: "Called the Blue Queen, with dark blue scales and wings.", + rider: "Prince Daeron Targaryen", + imageId: "tessarion", + size: "Medium", + primaryColor: "#00008B", + secondaryColor: "#4B0082", + age: "Young during the Dance of the Dragons", + notableAbilities: ["Beautiful appearance"] + }, + { + name: "Sheepstealer", + description: "An aggressive wild dragon with a taste for sheep, brown-scaled.", + rider: "Nettles", + imageId: "sheepstealer", + size: "Medium to large", + primaryColor: "#8B4513", + secondaryColor: "#2F4F4F", + age: "Unknown, but old", + notableAbilities: ["Wild and hard to tame", "Preference for eating sheep"] + }, + { + name: "Seasmoke", + description: "Pale silver-grey dragon ridden by Laenor Velaryon.", + rider: "Laenor Velaryon", + imageId: "seasmoke", + size: "Medium", + primaryColor: "#C0C0C0", + secondaryColor: "#4682B4", + age: "Young adult during the Dance of the Dragons", + notableAbilities: ["Swift flyer"] + }, + { + name: "Moondancer", + description: "Young, slender green dragon ridden by Baela Targaryen.", + rider: "Baela Targaryen", + imageId: "moondancer", + size: "Small to medium", + primaryColor: "#00FF00", + secondaryColor: "#006400", + age: "Very young during the Dance of the Dragons", + notableAbilities: ["Quick and nimble"] + }, + { + name: "Vermax", + description: "Young dragon ridden by Jacaerys Velaryon during the Dance of the Dragons.", + rider: "Jacaerys Velaryon", + imageId: "vermax", + size: "Small to medium", + primaryColor: "#808080", + secondaryColor: "#2F4F4F", + age: "Young during the Dance of the Dragons", + notableAbilities: ["Unknown"] + }, + { + name: "Arrax", + description: "Young dragon ridden by Lucerys Velaryon, described as swift.", + rider: "Lucerys Velaryon", + imageId: "arrax", + size: "Small", + primaryColor: "#808080", + secondaryColor: "#2F4F4F", + age: "Very young during the Dance of the Dragons", + notableAbilities: ["Swift flyer"] + }, + { + name: "Tyraxes", + description: "Young dragon ridden by Joffrey Velaryon, not much is known about its appearance.", + rider: "Joffrey Velaryon", + imageId: "tyraxes", + size: "Small", + primaryColor: "#808080", + secondaryColor: "#2F4F4F", + age: "Very young during the Dance of the Dragons", + notableAbilities: ["Unknown"] + } +]; diff --git a/public/fonts/gameofthrones.ttf b/public/fonts/gameofthrones.ttf Binary files differnew file mode 100644 index 0000000..793ddff --- /dev/null +++ b/public/fonts/gameofthrones.ttf diff --git a/public/images/dragon-sizes.png b/public/images/dragon-sizes.png Binary files differnew file mode 100644 index 0000000..064f1ff --- /dev/null +++ b/public/images/dragon-sizes.png diff --git a/public/images/hat-texas.gif b/public/images/hat-texas.gif Binary files differnew file mode 100644 index 0000000..b97734c --- /dev/null +++ b/public/images/hat-texas.gif diff --git a/public/images/pixel-lasso.jpeg b/public/images/pixel-lasso.jpeg Binary files differnew file mode 100644 index 0000000..c842197 --- /dev/null +++ b/public/images/pixel-lasso.jpeg diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..3e445c5 --- /dev/null +++ b/public/index.html @@ -0,0 +1,163 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Name my Dragon - Home</title> + <link rel="stylesheet" href="style.css"> +</head> +<body> + <center> + <h1>Name my Dragon</h1> + <audio id="audio-player" loop> + <source src="audio/western-cover.mp3" type="audio/mp3"> + Enable audio on your browser to get the best experience. + </audio> + <div class="alert"> + Warning: The button below will play some sweet tunes! + Hit the "Stop music" button to stop it or just mute your device. + <span class="closebtn" onclick="this.parentElement.style.display='none';">×</span> + </div> + <div class="container"> + <form id="nameForm" class="flex"> + <label style="color: black;" for="firstName">Enter your first name:</label> + <input type="text" id="firstName" placeholder="bob" required> + <button type="submit">Name my Dragon</button> + </form> + <div class="flex"> + <button id="stop-music" onclick="stopMusic();">Stop music</button> + </div> + </div> + <p>And your Dragon is...</p> + <div id="results" class="container"> + <div id="dragonName" class="flex flex1"></div> + <div id="dragonStats" class="flex flex2"></div> + <div id="lasso" class="flex"></div> + </div> + <div id="alternatives"></div> + <div> + <p>See a comparison of all the dragons here:</p> + <img src="images/dragon-sizes.png" width="50%" alt="Comparison chart for all the dragons"> + </div> + <footer> + <a href="about.html">How it works</a><br> + <a href="https://kumardamani.net" target="_blank">Author</a> + </footer> + </center> + + <script type="text/javascript" src="dragons.js"></script> + <script> + const dragonNames = dragons.map(d => d.name); + console.log(dragonNames); + + function levenshteinDistance(a, b) { + if (a.length === 0) return b.length; + if (b.length === 0) return a.length; + + const matrix = []; + + for (let i = 0; i <= b.length; i++) { + matrix[i] = [i]; + } + + for (let j = 0; j <= a.length; j++) { + matrix[0][j] = j; + } + + for (let i = 1; i <= b.length; i++) { + for (let j = 1; j <= a.length; j++) { + if (b.charAt(i - 1) === a.charAt(j - 1)) { + matrix[i][j] = matrix[i - 1][j - 1]; + } else { + matrix[i][j] = Math.min( + matrix[i - 1][j - 1] + 1, + matrix[i][j - 1] + 1, + matrix[i - 1][j] + 1 + ); + } + } + } + + return matrix[b.length][a.length]; + } + + function cosineSimilarity(a, b) { + const aSet = new Set(a.toLowerCase()); + const bSet = new Set(b.toLowerCase()); + const intersection = new Set([...aSet].filter(x => bSet.has(x))); + return intersection.size / Math.sqrt(aSet.size * bSet.size); + } + + function jaccardSimilarity(a, b) { + const aSet = new Set(a.toLowerCase()); + const bSet = new Set(b.toLowerCase()); + const intersection = new Set([...aSet].filter(x => bSet.has(x))); + const union = new Set([...aSet, ...bSet]); + return intersection.size / union.size; + } + + function calculateSimilarities(name) { + const results = dragonNames.map(n => ({ + name: n, + levenshtein: 1 - levenshteinDistance(name, n) / Math.max(name.length, n.length), + cosine: cosineSimilarity(name, n), + jaccard: jaccardSimilarity(name, n) + })); + + return { + levenshtein: results.sort((a, b) => b.levenshtein - a.levenshtein).slice(0, 5), + cosine: results.sort((a, b) => b.cosine - a.cosine).slice(0, 5), + jaccard: results.sort((a, b) => b.jaccard - a.jaccard).slice(0, 5) + }; + } + + function getDragonObject(name) { + return dragons.filter(dragon => (dragon.name === name))[0]; + } + + function stopMusic() { + document.getElementById('audio-player').pause(); + } + + document.getElementById('nameForm').addEventListener('submit', function(e) { + e.preventDefault(); + const name = document.getElementById('firstName').value; + const similarities = calculateSimilarities(name); + console.log(similarities); + + const topChoice = similarities.cosine[0].name; + const topChoiceDragon = getDragonObject(topChoice); + const possibleAlternatives = new Set( + Array.prototype.concat( + similarities.jaccard.slice(0, 2).map(n => n.name), + similarities.levenshtein.slice(0, 2).map(n => n.name) + ) + ).difference( + new Set([topChoice]) + ); + + document.getElementById('dragonName').innerHTML = + `<p><span style="font-size:xx-large;" class="legible">${topChoice}</span></p>`; + document.getElementById('dragonName').style.backgroundColor = topChoiceDragon.primaryColor; + + document.getElementById('dragonStats').innerHTML = ` + <p>${topChoiceDragon.description}</p> + <p> + Size: ${topChoiceDragon.size}<br> + Age: ${topChoiceDragon.age}<br> + Abilities: ${topChoiceDragon.notableAbilities}<br> + </p>`; + document.getElementById('dragonStats').style.backgroundColor = topChoiceDragon.secondaryColor; + + document.getElementById('lasso').innerHTML = ` + <img src="images/hat-texas.gif" width="100%" alt="Cowboy lasso gif">`; + document.getElementById('lasso').style.backgroundColor = topChoiceDragon.primaryColor; + + document.getElementById('alternatives').innerHTML = + `<p>Possible alternatives: <strong>${[...possibleAlternatives].join(', ')}</strong></p>`; + + document.getElementById('audio-player').play(); + }); + </script> +</body> +</html> diff --git a/public/style.css b/public/style.css new file mode 100644 index 0000000..9e664c4 --- /dev/null +++ b/public/style.css @@ -0,0 +1,88 @@ +@font-face { + font-family: 'GOTFont'; + src: url('fonts/gameofthrones.ttf'); +} + +html { + --s: 60px; /* control the size*/ + --c1: #b09f79; + --c2: #000000; + + --_g: #0000 83%,var(--c1) 85% 99%,#0000 101%; + background: + radial-gradient(27% 29% at right ,var(--_g)) calc(var(--s)/ 2) var(--s), + radial-gradient(27% 29% at left ,var(--_g)) calc(var(--s)/-2) var(--s), + radial-gradient(29% 27% at top ,var(--_g)) 0 calc(var(--s)/ 2), + radial-gradient(29% 27% at bottom,var(--_g)) 0 calc(var(--s)/-2) + var(--c2); + background-size: calc(2*var(--s)) calc(2*var(--s)); +} + +body { + background: #faf0e5; + opacity: 0.97; + padding: 10px; +} + +h1 { + font-family: 'GOTFont', Georgia, serif; +} + +.legible { + color: white; + text-shadow: + 0.05em 0 black, + 0 0.05em black, + -0.05em 0 black, + 0 -0.05em black, + -0.05em -0.05em black, + -0.05em 0.05em black, + 0.05em -0.05em black, + 0.05em 0.05em black; +} + +.container { + margin: 0; + padding: 0; + display: flex; + justify-content: center; + flex-wrap: wrap; +} + +.flex { + padding: 10px; + border: 3px solid #faf0e5; + color: white; + font-size: 14px; + text-align: center; + position: relative; + margin-bottom: 33px; +} + +.flex1 { + min-width: 150px; +} + +.flex2 { + font-size: large; + text-align: left; +} + +.alert { + margin-bottom: 15px; + padding: 20px; + background-color: orange; /* Red */ + color: white; +} + +/* The close button */ +.closebtn { + margin-left: 15px; + color: white; + font-weight: bold; + float: right; + font-size: 22px; + line-height: 20px; + cursor: pointer; + transition: 0.3s; +} |
