diff options
| author | Kumar Damani <me@kumardamani.net> | 2024-08-14 04:49:54 +0000 |
|---|---|---|
| committer | Kumar Damani <me@kumardamani.net> | 2024-08-14 04:49:54 +0000 |
| commit | a223c3fdaa7861d5f932ba2079dab5dfcf63bec5 (patch) | |
| tree | fcc8a2f90926e640f2205f391681e7a0300bb3c8 | |
Initial commit
| -rw-r--r-- | about.html | 35 | ||||
| -rw-r--r-- | audio/western-cover.m4a | bin | 0 -> 663447 bytes | |||
| -rw-r--r-- | dragons.js | 222 | ||||
| -rw-r--r-- | fonts/gameofthrones.ttf | bin | 0 -> 28784 bytes | |||
| -rw-r--r-- | images/dragon-sizes.png | bin | 0 -> 374143 bytes | |||
| -rw-r--r-- | images/hat-texas.gif | bin | 0 -> 161381 bytes | |||
| -rw-r--r-- | images/pink-panther-lasso-rope.gif | bin | 0 -> 756199 bytes | |||
| -rw-r--r-- | images/pixel-lasso.jpeg | bin | 0 -> 23529 bytes | |||
| -rw-r--r-- | index.html | 160 | ||||
| -rw-r--r-- | style.css | 71 |
10 files changed, 488 insertions, 0 deletions
diff --git a/about.html b/about.html new file mode 100644 index 0000000..c0536e2 --- /dev/null +++ b/about.html @@ -0,0 +1,35 @@ +<!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 in terms of its + "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 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> + <a href="index.html">Home</a> + </center> +</body> +</html> diff --git a/audio/western-cover.m4a b/audio/western-cover.m4a Binary files differnew file mode 100644 index 0000000..193a465 --- /dev/null +++ b/audio/western-cover.m4a diff --git a/dragons.js b/dragons.js new file mode 100644 index 0000000..5dd3ecb --- /dev/null +++ b/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/fonts/gameofthrones.ttf b/fonts/gameofthrones.ttf Binary files differnew file mode 100644 index 0000000..793ddff --- /dev/null +++ b/fonts/gameofthrones.ttf diff --git a/images/dragon-sizes.png b/images/dragon-sizes.png Binary files differnew file mode 100644 index 0000000..064f1ff --- /dev/null +++ b/images/dragon-sizes.png diff --git a/images/hat-texas.gif b/images/hat-texas.gif Binary files differnew file mode 100644 index 0000000..b97734c --- /dev/null +++ b/images/hat-texas.gif diff --git a/images/pink-panther-lasso-rope.gif b/images/pink-panther-lasso-rope.gif Binary files differnew file mode 100644 index 0000000..538ff06 --- /dev/null +++ b/images/pink-panther-lasso-rope.gif diff --git a/images/pixel-lasso.jpeg b/images/pixel-lasso.jpeg Binary files differnew file mode 100644 index 0000000..c842197 --- /dev/null +++ b/images/pixel-lasso.jpeg diff --git a/index.html b/index.html new file mode 100644 index 0000000..785667b --- /dev/null +++ b/index.html @@ -0,0 +1,160 @@ +<!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.m4a" type="audio/mp4"> + 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> + <a href="about.html">How it works</a> + </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/style.css b/style.css new file mode 100644 index 0000000..9445212 --- /dev/null +++ b/style.css @@ -0,0 +1,71 @@ +@font-face { + font-family: 'GOTFont'; + src: url('fonts/gameofthrones.ttf'); +} + +body { + background: #faf0e5 +} + +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; +} |
