About this Code
Hello reader, I am chris22smith. Nice to meet you again in this free code sharing website. In this post I am going to explain about Racing Name Picker.
If you are new to this website, we recommend you to subscribe to our youtube channel and watch the videos. Ok lets dive into the code.
Images
These are the output images of the code. You can click on the image to enlarge it. also you can click the try it button to see the output.
Youtube Tutorial Video
If you are a visual learner and want to learn how to use this code, you can watch the video below.
and also this video contains the clear step by step explanation and the output of the code.
VIDEO
Source Code
This is the source code of the code. You can copy and paste the code to your editor.
@charset "UTF-8";
@import url(https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,600,700,800);
*,
:after,
:before {
box-sizing: border-box;
padding: 0;
margin: 0;
}
:root {
--moveTime: 500ms;
}
body {
background-image: linear-gradient(#446, #222);
block-size: 100dvh;
font-family: sans-serif;
display: flex;
inline-size: 100dvw;
margin: 0;
}
main {
flex: 1 0 auto;
padding: 0 2rem;
}
h1 {
color: hotpink;
filter: drop-shadow(0 0 .1em #000);
font-size: 6vw;
margin: 0;
padding: 1rem 0;
text-align: center;
text-transform: uppercase;
}
aside {
background-color: #222;
color: #ccc;
flex: 0 1 auto;
padding: 0 2rem;
}
#names {
background-color: #444;
border: solid 1px #ccc;
box-sizing: border-box;
color: #ccc;
inline-size: 100%;
margin-block-start: .5rem;
padding: .5rem;
}
#emoji {
background-color: #444;
border: solid 1px #ccc;
box-sizing: border-box;
font-size: 2rem;
inline-size: 4rem;
margin-block-start: .5rem;
padding: .5rem;
text-align: center;
}
#lanes {
background-color: #ccc;
background-image:linear-gradient(#ccc, #bbb);
border-inline-start: solid 2px hotpink;
list-style: none;
margin: 0 0 1rem 0;
padding: 0 2rem;
> li {
block-size: 4rem;
position: relative;
& + li {
border-top: dashed 2px #fff;
}
&:nth-child(6n - 5) {
filter: hue-rotate(0deg);
}
&:nth-child(6n - 1) {
filter: hue-rotate(60deg);
}
&:nth-child(6n - 3) {
filter: hue-rotate(120deg);
}
&:nth-child(6n - 4) {
filter: hue-rotate(180deg);
}
&:nth-child(6n - 2) {
filter: hue-rotate(240deg);
}
&:nth-child(6n) {
filter: hue-rotate(300deg);
}
}
}
.racer {
display: inline-block;
font-size: 2rem;
position: absolute;
right: -2rem;
top: 1rem;
transition: right var(--moveTime) linear;
.emoji {
display: inline-block;
}
.name {
font-size: small;
left: 0;
position: absolute;
right: 0;
text-align: center;
top: -0.75rem;
}
}
.active .emoji {
animation: tilt-n-move-shaking 0.25s infinite .5s;
}
.button-panel {
text-align: end;
}
#go, #reset {
animation: pulse 2s infinite;
border: none;
}
#go {
background-color: hotpink;
border-radius: 50%;
block-size: 3rem;
font-weight: bold;
inline-size: 3rem;
}
#reset {
background-color: hotpink;
border-radius: 1rem;
color: #fff;
padding: .5rem 1rem;
}
main > p {
text-align: center;
}
#commentary {
background-color: #fff;
border-radius: 1rem;
display: inline-block;
font-size: 1.5rem;
padding: .5rem 1rem;
&:empty {
padding: 0;
}
}
@keyframes tilt-n-move-shaking {
0% { transform: translate(0, 0) rotate(0deg); }
25% { transform: translate(1px, 1px) rotate(1deg); }
50% { transform: translate(0, 0) rotate(0eg); }
75% { transform: translate(-1px, 1px) rotate(-1deg); }
100% { transform: translate(0, 0) rotate(0deg); }
}
@keyframes pulse {
0% {
transform: scale(0.95);
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.7);
}
70% {
transform: scale(1);
box-shadow: 0 0 0 1rem rgba(0, 0, 0, 0);
}
100% {
transform: scale(0.95);
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
}
}
console.log("Event Fired")
const names = document.querySelector("#names");
const emojiInput = document.querySelector("#emoji");
const lanes = document.querySelector("#lanes");
const go = document.querySelector("#go");
const reset = document.querySelector("#reset");
const commentary = document.querySelector("#commentary");
const boosts = [1, 2, 3, 5];
const moveTime = 400;
// loaded from CDN
const jsConfetti = new JSConfetti();
let list = [];
let loop = undefined;
let previousLeader = undefined;
const defaultList = [
{ name: "A", score: 0 },
{ name: "B", score: 0 },
{ name: "C", score: 0 },
{ name: "D", score: 0 }
];
// ---------- settings ----------
const getListFromTextarea = () => {
let lines = names.value.split("\n");
lines = lines.filter(Boolean); // removes any empty strings
list = lines.map(line => {
return { name: line, score: 0};
});
};
const getRandomItem = () => {
getListFromTextarea();
return list.length ? list[Math.floor(list.length * Math.random())].name : "No items found";
}
const updateStoredList = () => {
getListFromTextarea();
localStorage.setItem("list", JSON.stringify(list));
updateItemsList();
};
const loadStoredList = () => {
list = JSON.parse(localStorage.getItem("list")) || defaultList;
const items = list.map(i => i.name);
names.value = items.join("\n");
updateItemsList();
}
const checkIfWeHaveEnoughRacers = () => {
go.hidden = lanes.children.length < 2;
};
const updateItemsList = () => {
lanes.innerHTML = "";
const emoji = emojiInput.value || "🚴";
const frag = document.createDocumentFragment();
list.forEach((item) => {
if (item.name && item.name.length) {
const li = document.createElement("li");
li.innerHTML = `${emoji} ${item.name} `;
frag.appendChild(li);
}
});
lanes.appendChild(frag);
checkIfWeHaveEnoughRacers();
};
// ---------- race mechanics ----------
const randomBoost = () => {
return boosts[Math.floor(boosts.length * Math.random())];
};
const randomRacerIndex = () => {
return Math.floor(list.length * Math.random());
};
const checkForWin = () => {
const winner = list.find(item => item.score > 99);
if (winner) {
clearTimeout(loop);
setTimeout(() => {
reset.hidden = false;
commentary.textContent = `${winner.name} wins! 🏆`;
jsConfetti.addConfetti();
}, moveTime * 1.5);
lanes.classList.remove("active");
}
return;
};
const randomPhrase = () => {
const phrases = [
"takes the lead",
"is ahead",
"in the lead",
"is winning",
"leading",
"at the front",
"is first"
];
return phrases[Math.floor(phrases.length * Math.random())];
};
const move = () => {
const racerIndex = randomRacerIndex();
const boost = randomBoost();
list.forEach((racer, index) => {
racer.score++;
if (index === racerIndex) {
racer.score += boost;
}
});
list.forEach((item, index) => {
const racer = lanes.querySelector(`li:nth-child(${index + 1}) .racer`);
racer.style.right = `${list[index].score}%`;
});
// get index of highest score
const winning = list.map(item => item.score).reduce((iMax, x, i, arr) => x > arr[iMax] ? i : iMax, 0);
if (winning !== previousLeader) {
const winner = list.map(item => item.name)[winning];
const phrase = randomPhrase();
commentary.textContent = `${winner} ${phrase}`;
previousLeader = winning;
}
checkForWin();
};
const race = () => {
commentary.textContent = "And they're off";
go.hidden = true;
lanes.classList.add("active");
names.disabled = true;
emojiInput.disabled = true;
loop = setInterval(() => {
move();
}, moveTime);
}
const startAgain = () => {
list.forEach(item => item.score = 0);
[...lanes.querySelectorAll(".racer")].forEach(racer => {
racer.style.right = "-2rem";
})
reset.hidden = true;
go.hidden = false;
commentary.textContent = "";
names.disabled = false;
emojiInput.disabled = false;
jsConfetti.clearCanvas();
};
// ---------- events -----------
emojiInput.addEventListener("change", updateItemsList);
names.addEventListener("input", updateStoredList);
go.addEventListener("click", race);
reset.addEventListener("click", startAgain);
window.onload = loadStoredList;
And also you can click the try it button to see the output of the code in our web Code Playground.
You can also download the code to the zip format by clicking the download button. The download process is little bit complex, you need ti await for 10 seconds. after that you can download the code by clicking the generated download link.
Leave a Comment
You need to login first to comment.