
Organize the Scrolls
Your First Day as an Intern
Ah, my brave apprentice, if you are reading this, you are ready to delve into the depths of JavaScript sorcery. I’ve gathered for you a selection of treasured spells I once discovered on the ancient W3 scrolls. But beware! If the scrolls are carelessly bound, your project may soon resemble the aftermath of a botched transformation spell.
To prevent such chaos, you’ll find an example included: a navigation system that elegantly adapts to any screen size. Your task now is to rearrange the scattered scrolls and place them neatly in an organized directory. Follow the instructions closely, and with each line of code, you will uncover another secret—until the true power of the script is revealed to you.
– Yours, Morrigan
The spark of interactivity
This is how your page comes to life!

JavaScript Integration
Step-by-step guide
1. Create a folder for your project
Create a new folder with a resonant name. Open this folder in Visual Studio Code by clicking on File > Open Folder and selecting your newly created folder.
2. Create the HTML scroll
Create a file named index.html by right-clicking inside the project folder and selecting New File. Copy the following HTML code into it and make sure to include the CSS and JavaScript paths in the <head> and <script> sections.
Create the CSS scroll
Create a new file named style.css in the same folder. This scroll defines the visual appearance of the scripts—colors, spacing, and flexibility. Copy the following CSS code into it and save the file.
Responsive Menu
Perfect transition from large to small monitors
<!-- HTML -->
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Link to Font Awesome for the magical icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<!-- Link to the magical cloak (CSS file) -->
</head>
<body>
<!-- The legendary navigation menu -->
<div class="topnav">
<!-- The mysterious title -->
<a href="#home" class="brand-title">Aetheron Emporium</a>
<!-- The real treasure: the links! -->
<div class="topnav-links" id="topnavLinks">
<a href="#news">News</a>
<a href="#contact">Contact</a>
<a href="#about">About</a>
</div>
<!-- The magical menu icon that moves things -->
<a href="javascript:void(0);" class="icon" onclick="toggleMenu()">
<i class="fas fa-bars"></i>
</a>
</div>
<!-- The reference to the spellbook (JavaScript) -->
</body>
</html>
/* Magic for everything: removes unwanted margins and padding */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
}
body {
font-size: 16px;
}
/* The magnificent shell of the navigation */
.topnav {
display: flex;
align-items: center;
justify-content: space-between;
background-color: #333;
padding: 1rem;
}
/* The mystical title at the top */
.brand-title {
color: #f0e68c;
font-size: 1.5rem;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 2px;
text-decoration: none;
}
/* Colors for links to make them shine and glow */
.topnav a {
color: #f2f2f2;
text-decoration: none;
padding: 0.5rem 1rem;
font-size: 1rem;
transition: background-color 0.3s;
}
.topnav a:hover {
background-color: #575757;
}
/* The secret symbol remains invisible at first */
.topnav .icon {
display: none;
color: #f2f2f2;
font-size: 1.5rem;
}
/* The left side of the navigation */
.topnav-links {
display: flex;
gap: 1rem;
}
/* When the screen shrinks: the layout magically adapts */
@media screen and (max-width: 600px) {
.topnav-links {
display: none;
/* Links cleverly hide */
flex-direction: column;
width: 100%;
background-color: #333;
position: absolute;
top: 60px;
left: 0;
}
/* When 'responsive' is summoned, the menu reveals itself */
.topnav-links.responsive {
display: flex;
}
/* The symbol now appears large and bright */
.topnav .icon {
display: block;
}
}
// JavaScript
// Function that unleashes the menu magic
function toggleMenu() {
// Retrieve the menu element from its disguise
const navLinks = document.getElementById('topnavLinks');
// Toggle the 'responsive' class to show or hide it
navLinks.classList.toggle('responsive');
}
Overlay Nav
Always one of the most beautiful navigations
<!-- HTML -->
<!-- Button to open the navigation -->
<button id="openNav" class="open-btn">☰ Open Navigation</button>
<!-- Fullscreen overlay navigation -->
<div id="myNav" class="overlay">
<a href="javascript:void(0)" class="closebtn">×</a>
<div class="overlay-content">
<a href="#" class="closeNav">Home</a>
<a href="#" class="closeNav">Services</a>
<a href="#" class="closeNav">About</a>
<a href="#" class="closeNav">Contact</a>
</div>
</div>
/* CSS */
/* The navigation covers the entire screen width but starts at width 0 */
.overlay {
height: 100%;
width: 0;
position: fixed;
z-index: 1;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, 0.9);
overflow-x: hidden;
transition: width 0.5s ease;
}
/* The overlay content stays centered */
.overlay-content {
position: relative;
top: 50%;
width: 100%;
text-align: center;
transform: translateY(-50%);
}
.overlay-content a {
padding: 15px;
text-decoration: none;
font-size: 30px;
color: white;
display: block;
transition: color 0.3s;
}
.overlay-content a:hover {
color: coral;
}
/* Close button */
.closebtn {
position: absolute;
top: 20px;
right: 45px;
font-size: 60px;
color: white;
text-decoration: none;
}
/* The button to open */
.open-btn {
font-size: 20px;
padding: 10px 20px;
background-color: coral;
color: white;
border: none;
cursor: pointer;
}
// JavaScript
// Open the navigation
document.getElementById('openNav').addEventListener('click', () => {
// document.getElementById('myNav').style.height = '100%';
document.getElementById('myNav').style.width = '100%';
});
// Close the navigation when clicking on a link or the close button
const closeNavElements = document.querySelectorAll('.closeNav, .closebtn');
closeNavElements.forEach(element => {
element.addEventListener('click', () => {
// document.getElementById('myNav').style.height = '0%';
document.getElementById('myNav').style.width = '0%';
});
});
Slideshow
Let your images run
<!-- HTML -->
<div class="slideshow-container">
<!-- Slide 1 -->
<div class="slide fade">
<img src="assets/img/news/caelan.jpg" style="width:100%" alt="Slide 1">
</div>
<!-- Slide 2 -->
<div class="slide fade">
<img src="assets/img/news/fungus.jpg" style="width:100%" alt="Slide 2">
</div>
<!-- Slide 3 -->
<div class="slide fade">
<img src="assets/img/news/sonya.jpg" style="width:100%" alt="Slide 3">
</div>
<!-- Navigation Arrows -->
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
</div>
<!-- Dots -->
<div class="dot-container">
<span class="dot" onclick="currentSlide(1)"></span>
<span class="dot" onclick="currentSlide(2)"></span>
<span class="dot" onclick="currentSlide(3)"></span>
</div>
/* CSS */
* {
box-sizing: border-box;
}
.slideshow-container {
position: relative;
margin: auto;
max-width: 800px;
}
/* Each slide */
.slide {
display: none;
position: relative;
width: 100%;
}
/* Fade effect */
.fade {
animation-name: fade;
animation-duration: 1.5s;
}
@keyframes fade {
from {
opacity: 0.4;
}
to {
opacity: 1;
}
}
/* Navigation arrows */
.prev,
.next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
padding: 16px;
margin-top: -22px;
color: white;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
user-select: none;
background-color: rgba(0, 0, 0, 0.5);
}
.next {
right: 0;
}
.prev:hover,
.next:hover {
background-color: rgba(0, 0, 0, 0.8);
}
/* Dots (navigation indicators) */
.dot-container {
text-align: center;
padding: 20px;
}
.dot {
cursor: pointer;
height: 15px;
width: 15px;
margin: 0 4px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
}
.active,
.dot:hover {
background-color: #717171;
}
// JavaScript
let slideIndex = 0;
const slides = document.getElementsByClassName("slide");
const dots = document.getElementsByClassName("dot");
// Displays the current slide
function showSlide(n) {
if (n >= slides.length) { slideIndex = 0; }
if (n < 0) { slideIndex = slides.length - 1; }
// Hide all slides
for (let i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
// Reset all dots
for (let i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex].style.display = "block";
dots[slideIndex].className += " active";
}
// Manual navigation (arrows)
function plusSlides(n) {
slideIndex += n;
showSlide(slideIndex);
}
// Direct jump to a specific slide (dots)
function currentSlide(n) {
slideIndex = n - 1;
showSlide(slideIndex);
}
// Automatic slideshow change
function autoSlide() {
slideIndex++;
if (slideIndex >= slides.length) { slideIndex = 0; }
showSlide(slideIndex);
setTimeout(autoSlide, 5000); // Switches every 5 seconds
}
// Initial call
showSlide(slideIndex);
setTimeout(autoSlide, 5000);
Slideshow with text
Add captions to your running images
<!-- HTML -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Slideshow with Text Overlay</title>
</head>
<body>
<div class="slideshow-container">
<!-- Slide 1 -->
<div class="slide fade">
<img src="assets/img/world/greenwood-hollow.jpg" alt="Slide 1">
<div class="slide-text">
<h2>Headline 1</h2>
<p>This is the subline for Slide 1.</p>
</div>
</div>
<!-- Slide 2 -->
<div class="slide fade">
<img src="assets/img/world/skyterranova.jpg" alt="Slide 2">
<div class="slide-text">
<h2>Headline 2</h2>
<p>Here is the subline for Slide 2.</p>
</div>
</div>
<!-- Slide 3 -->
<div class="slide fade">
<img src="assets/img/world/sunnyside-fields.jpg" alt="Slide 3">
<div class="slide-text">
<h2>Headline 3</h2>
<p>Subline for Slide 3 - more information.</p>
</div>
</div>
<!-- Navigation Arrows -->
<a class="prev" onclick="plusSlides(-1)">❮</a>
<a class="next" onclick="plusSlides(1)">❯</a>
<!-- Dots -->
<div class="dot-container">
<span class="dot" onclick="currentSlide(1)"></span>
<span class="dot" onclick="currentSlide(2)"></span>
<span class="dot" onclick="currentSlide(3)"></span>
</div>
</div>
</body>
</html>
/* CSS */
/* Container for the entire slideshow */
.slideshow-container {
position: relative;
margin: auto;
max-width: 1000px;
overflow: hidden;
}
/* Each slide */
.slide {
display: none;
position: relative;
}
/* Image styling */
.slide img {
width: 100%;
vertical-align: middle;
}
/* Text overlay */
.slide-text {
position: absolute;
bottom: 20%;
left: 50%;
transform: translateX(-50%);
color: #fff;
text-align: center;
background: rgba(0, 0, 0, 0.5);
/* Semi-transparent background */
padding: 20px;
border-radius: 10px;
}
.slide-text h2 {
font-size: 2.5em;
margin: 0;
}
.slide-text p {
font-size: 1.2em;
margin-top: 10px;
}
/* Fade effect */
.fade {
animation-name: fade;
animation-duration: 1.5s;
}
@keyframes fade {
from {
opacity: 0.4;
}
to {
opacity: 1;
}
}
/* Navigation arrows */
.prev,
.next {
cursor: pointer;
position: absolute;
top: 50%;
width: auto;
padding: 16px;
margin-top: -22px;
color: white;
font-weight: bold;
font-size: 18px;
transition: 0.6s ease;
user-select: none;
background-color: rgba(0, 0, 0, 0.5);
}
.prev {
left: 0;
}
.next {
right: 0;
}
.prev:hover,
.next:hover {
background-color: rgba(0, 0, 0, 0.8);
}
/* Dots for navigation */
.dot-container {
text-align: center;
position: absolute;
bottom: 10px;
width: 100%;
}
.dot {
cursor: pointer;
height: 15px;
width: 15px;
margin: 0 2px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
}
.active,
.dot:hover {
background-color: #717171;
}
// JavaScript
let slideIndex = 0;
const slides = document.getElementsByClassName("slide");
const dots = document.getElementsByClassName("dot");
// Show the current slide and update the dots
function showSlide(n) {
if (n >= slides.length) { slideIndex = 0; }
if (n < 0) { slideIndex = slides.length - 1; }
for (let i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
for (let i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex].style.display = "block";
dots[slideIndex].className += " active";
}
// Automatic slide switching
function autoSlide() {
slideIndex++;
if (slideIndex >= slides.length) { slideIndex = 0; }
showSlide(slideIndex);
setTimeout(autoSlide, 5000); // Switches every 5 seconds
}
// Manual navigation via arrows
function plusSlides(n) {
slideIndex += n;
showSlide(slideIndex);
}
// Jump directly to a specific slide (dots)
function currentSlide(n) {
slideIndex = n - 1;
showSlide(slideIndex);
}
// Initial call
showSlide(slideIndex);
setTimeout(autoSlide, 5000);
Image gallery
For your travel journal
<!-- HTML -->
<h1>Image Gallery</h1>
<div class="gallery">
<img src="assets/img/future/communication.jpg" alt="Tis is Image 1" title="Titel Bild 1">
<img src="assets/img/enemies/umbra.jpg" alt="Tis is Image 2" title="Titel Bild 2">
<img src="assets/img/heroes/gart.jpg" alt="Tis is Image 3" title="Titel Bild 3">
<img src="assets/img/news/fungus.jpg" alt="Tis is Image 4" title="Titel Bild 4">
<img src="assets/img/news/sonya.jpg" alt="Tis is Image 5" title="Titel Bild 5">
<img src="assets/img/heroes/seraphina.jpg" alt="Tis is Image 6" title="Titel Bild 6">
<img src="assets/img/future/new-ironspire.jpg" alt="Tis is Image 7" title="Titel Bild 7">
<img src="assets/img/news/gingerbread.jpg" alt="Tis is Image 8" title="Titel Bild 8">
<!-- More pictures here -->
</div>
<!-- Overlay Lightbox -->
<div class="overlay" id="overlay">
<span class="close-button" onclick="closeOverlay()">×</span>
<div class="overlay-content">
<img id="overlay-image" src="" alt="">
<div class="overlay-text">
<h2 id="overlay-title"></h2>
<p id="overlay-alt"></p>
</div>
</div>
</div>
/* CSS */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background: #f4f4f4;
}
h1 {
text-align: center;
padding: 20px 0;
}
/* Masonry Gallery */
.gallery {
column-count: 3;
column-gap: 1em;
max-width: 1200px;
margin: 0 auto;
padding: 1em;
}
.gallery img {
width: 100%;
margin-bottom: 1em;
display: inline-block;
cursor: pointer;
border-radius: 5px;
transition: transform 0.3s;
}
.gallery img:hover {
transform: scale(1.05);
}
/* Overlay Modal */
.overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: none;
align-items: center;
justify-content: center;
z-index: 1000;
}
.overlay-content {
position: relative;
max-width: 90%;
max-height: 90%;
text-align: center;
}
.overlay-content img {
max-width: 100%;
max-height: 80vh;
border-radius: 5px;
}
.overlay-text {
color: #fff;
margin-top: 10px;
}
.overlay-text h2 {
margin: 10px 0 5px;
font-size: 24px;
}
.overlay-text p {
margin: 0;
font-size: 16px;
}
.close-button {
position: absolute;
top: 10px;
right: 15px;
font-size: 40px;
color: #fff;
cursor: pointer;
}
@media (max-width: 768px) {
.gallery {
column-count: 2;
}
}
@media (max-width: 480px) {
.gallery {
column-count: 1;
}
}
// JavaScript
// Event listener for all images in the gallery
const galleryImages = document.querySelectorAll('.gallery img');
galleryImages.forEach(img => {
img.addEventListener('click', function () {
openOverlay(this);
});
});
function openOverlay(img) {
// Set image source, alt text, and title in the overlay
document.getElementById('overlay-image').src = img.src;
document.getElementById('overlay-image').alt = img.alt;
document.getElementById('overlay-title').textContent = img.title;
document.getElementById('overlay-alt').textContent = img.alt;
document.getElementById('overlay').style.display = 'flex';
}
function closeOverlay() {
document.getElementById('overlay').style.display = 'none';
}
// Close the overlay when clicking outside the content
document.getElementById('overlay').addEventListener('click', function (e) {
if (e.target === this) {
closeOverlay();
}
});
Lightbox
So everyone can see your images in full size
<!-- HTML -->
<div class="container">
<div>
<img src="assets/img/future/communication.jpg" alt="" class="img-gallery img">
</div>
<div>
<img src="assets/img/future/conversion.jpg" alt="" class="img-gallery img">
</div>
<div>
<video src="assets/media/mushroom-forest.mp4" loop autoplay muted class="img-gallery img"></video>
</div>
</div>
<!-- Lightbox Overlay -->
<div class="overlay-gallery" id="lightboxOverlay">
<span class="close-btn" id="closeBtn">×</span>
<!-- Large Image -->
<img id="lightboxImage" alt="Enlarged view" style="display: none;">
<!-- Large Video -->
<video id="lightboxVideo" controls style="display: none;"></video>
</div>
/* CSS */
.container {
max-width: 1200px;
display: flex;
flex-wrap: wrap;
gap: 15px;
}
.container>div {
flex: 1 1 15rem;
}
.img {
max-width: 100%;
height: auto;
cursor: pointer;
}
/* Lightbox */
/* The overlay covers the entire screen */
.overlay-gallery {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
/* Start: invisible */
justify-content: center;
align-items: center;
background-color: #0000007d;
/* Dark overlay */
z-index: 9999;
}
/* The close button (X) */
.close-btn {
position: absolute;
top: 20px;
right: 30px;
font-size: 2rem;
color: #fff;
cursor: pointer;
}
/* Max size of the embedded image/video in the lightbox */
#lightboxImage,
#lightboxVideo {
max-width: 90%;
max-height: 90%;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.8);
border-radius: 8px;
}
// JavaScript
// Lightbox
// References to the overlay elements
const lightboxOverlay = document.getElementById('lightboxOverlay');
const lightboxImage = document.getElementById('lightboxImage');
const lightboxVideo = document.getElementById('lightboxVideo');
const closeBtn = document.getElementById('closeBtn');
// All gallery elements that have the "img-gallery" class
const galleryItems = document.querySelectorAll('.img-gallery');
galleryItems.forEach(item => {
item.addEventListener('click', () => {
// First hide both image and video so that both aren't shown at the same time
lightboxImage.style.display = 'none';
lightboxVideo.style.display = 'none';
lightboxVideo.pause(); // Pause the video just in case
// Check if it's an IMG or VIDEO
if (item.tagName.toLowerCase() === 'img') {
// Set image source
lightboxImage.src = item.src;
lightboxImage.style.display = 'block';
} else if (item.tagName.toLowerCase() === 'video') {
// Set video source
lightboxVideo.src = item.src;
lightboxVideo.style.display = 'block';
lightboxVideo.play();
}
// Show overlay
lightboxOverlay.style.display = 'flex';
});
});
// Click on the "X" -> Close overlay
closeBtn.addEventListener('click', () => {
lightboxOverlay.style.display = 'none';
lightboxVideo.pause(); // Stop the video if present
});
// Click on overlay background -> Close overlay
lightboxOverlay.addEventListener('click', (event) => {
// Only close if the background (not the image/video) is clicked
if (event.target === lightboxOverlay) {
lightboxOverlay.style.display = 'none';
lightboxVideo.pause();
}
});
Modal
A popup with content
<!-- HTML -->
<h2>Modal Example</h2>
<!-- Button to open the modal -->
<button id="openModalBtn">Open Modal</button>
<!-- The Modal -->
<div id="myModal" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span class="close" id="closeModalBtn">×</span>
<h2>Modal Heading</h2>
<p>This is a sample text inside the modal. Additional content, forms, or information can be displayed here.</p>
</div>
</div>
/* CSS */
/* Basic modal styling */
.modal {
display: none;
/* Hidden by default */
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
/* Allows scrolling if needed */
background-color: rgba(0, 0, 0, 0.5);
/* Semi-transparent background */
}
/* Modal content */
.modal-content {
background-color: #fff;
margin: 15% auto;
/* Centers the modal horizontally */
padding: 20px;
border: 1px solid #888;
width: 80%;
max-width: 500px;
border-radius: 5px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
/* Close button */
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover,
.close:focus {
color: #000;
text-decoration: none;
}
// JavaScript
// Select elements
const modal = document.getElementById("myModal");
const openModalBtn = document.getElementById("openModalBtn");
const closeModalBtn = document.getElementById("closeModalBtn");
// Open modal when the button is clicked
openModalBtn.addEventListener("click", function () {
modal.style.display = "block";
});
// Close modal when the close symbol is clicked
closeModalBtn.addEventListener("click", function () {
modal.style.display = "none";
});
// Close modal when clicking outside the modal content
window.addEventListener("click", function (event) {
if (event.target === modal) {
modal.style.display = "none";
}
});
Audio Player
Design your own player and replace boring buttons with icons
<!-- HTML -->
<audio id="myAudio">
<source src="assets/media/night-whisper.mp3" type="audio/mpeg" loop>
Your browser does not support the audio tag.
</audio>
<button onclick="playAudio()" type="button">▶</button>
<button onclick="pauseAudio()" type="button">■</button>
// JavaScript
const x = document.getElementById("myAudio");
function playAudio() {
x.play();
}
function pauseAudio() {
x.pause();
}
Accordion
Hide lots of content in a clear and compact way
<!-- HTML -->
<h2>Accordion Example</h2>
<div class="accordion">
<div class="accordion-item">
<button class="accordion-header">Section 1</button>
<div class="accordion-content">
<p>This is the content of Section 1. Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
</div>
</div>
<div class="accordion-item">
<button class="accordion-header">Section 2</button>
<div class="accordion-content">
<p>This is the content of Section 2. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
</div>
<div class="accordion-item">
<button class="accordion-header">Section 3</button>
<div class="accordion-content">
<p>This is the content of Section 3. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip.</p>
</div>
</div>
</div>
/* CSS */
/* Accordion Container */
.accordion {
width: 80%;
max-width: 800px;
margin: 20px auto;
border: 1px solid #ccc;
border-radius: 4px;
overflow: hidden;
}
/* Single Accordion Item */
.accordion-item {
border-bottom: 1px solid #ccc;
}
/* Accordion Header */
.accordion-header {
background-color: #f1f1f1;
cursor: pointer;
padding: 15px;
font-size: 1.1em;
border: none;
text-align: left;
outline: none;
transition: background-color 0.3s ease;
width: 100%;
}
.accordion-header.active {
background-color: #ddd;
}
/* Accordion Content with Smooth Transition */
.accordion-content {
max-height: 0;
overflow: hidden;
background-color: #fff;
transition: max-height 0.5s ease;
padding: 0 15px;
}
.accordion-content p {
margin: 15px 0;
}
// JavaScript
const headers = document.querySelectorAll('.accordion-header');
headers.forEach(header => {
header.addEventListener('click', function () {
const content = this.nextElementSibling;
// If the current panel is already open, close it
if (content.style.maxHeight) {
content.style.maxHeight = null;
this.classList.remove('active');
} else {
// First, close all other panels
document.querySelectorAll('.accordion-content').forEach(item => {
item.style.maxHeight = null;
if (item.previousElementSibling.classList.contains('active')) {
item.previousElementSibling.classList.remove('active');
}
});
// Then open the clicked panel
content.style.maxHeight = content.scrollHeight + "px";
this.classList.add('active');
}
});
});
Tab Menu
Organize large amounts of content neatly
<!-- HTML -->
<div class="tab-container">
<div class="tab-buttons">
<!-- Buttons to switch tabs -->
<button class="tab-link active" onclick="openTab(event, 'tab1')">Tab 1</button>
<button class="tab-link" onclick="openTab(event, 'tab2')">Tab 2</button>
<button class="tab-link" onclick="openTab(event, 'tab3')">Tab 3</button>
</div>
<!-- Content of Tab 1 -->
<div id="tab1" class="tab-content active">
<h2>Content of Tab 1</h2>
<p>This is the content of the first tab. You can place information, images, or other content here.</p>
</div>
<!-- Content of Tab 2 -->
<div id="tab2" class="tab-content">
<h2>Content of Tab 2</h2>
<p>This is the content of the second tab. You can customize this area as you like.</p>
</div>
<!-- Content of Tab 3 -->
<div id="tab3" class="tab-content">
<h2>Content of Tab 3</h2>
<p>This is the content of the third tab. Add more content here.</p>
</div>
</div>
/* CSS */
/* Container for the tab menu */
.tab-container {
width: 80%;
max-width: 800px;
margin: 20px auto;
font-family: Arial, sans-serif;
}
/* Tab buttons */
.tab-buttons {
overflow: hidden;
border-bottom: 1px solid #ccc;
}
.tab-buttons button {
background-color: #f1f1f1;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: background-color 0.3s;
font-size: 17px;
}
.tab-buttons button:hover {
background-color: #ddd;
}
.tab-buttons button.active {
background-color: #ccc;
}
/* Tab contents */
.tab-content {
display: none;
padding: 20px;
border: 1px solid #ccc;
border-top: none;
animation: fadeIn 0.5s;
}
.tab-content.active {
display: block;
}
/* Smooth fade-in animation */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
// JavaScript
function openTab(evt, tabName) {
var i, tabcontent, tablinks;
// Hide all tab contents
tabcontent = document.getElementsByClassName("tab-content");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].classList.remove("active");
}
// Remove active class from all buttons
tablinks = document.getElementsByClassName("tab-link");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].classList.remove("active");
}
// Show the selected tab content and mark button as active
document.getElementById(tabName).classList.add("active");
evt.currentTarget.classList.add("active");
}
Lettering
Make letters appear as if written by an invisible hand!
<!-- HTML -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Typewriter Effect with Typed.js</title>
<!-- Typed.js via CDN -->
<script src="https://cdn.jsdelivr.net/npm/typed.js@2.0.12"></script>
</head>
<body>
<div class="typed-container">
<span id="typed"></span>
</div>
</body>
</html>
/* CSS */
body {
margin: 0;
background: #111;
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
color: #fff;
font-family: 'Courier New', monospace;
}
.typed-container {
font-size: 2rem;
text-align: center;
}
// JavaScript This is where your text goes
const options = {
strings: [
"Welcome to the magical world of Aetheron.",
"Experience magic, technology, and unforgettable adventures.",
"Dive into the mystery of the ancient chronicles."
],
typeSpeed: 50,
backSpeed: 25,
loop: true,
backDelay: 2000,
showCursor: true,
cursorChar: '|'
};
const typed = new Typed("#typed", options);
Countdown
Enter your time and get reminded with music
<!-- HTML -->
<div class="container">
<h1>Countdown Timer</h1>
<p>Enter the time in hours, minutes, and seconds:</p>
<input type="number" id="hoursInput" placeholder="Hours" min="0">
<input type="number" id="minutesInput" placeholder="Minutes" min="0" max="59">
<input type="number" id="secondsInput" placeholder="Seconds" min="0" max="59">
<button onclick="startCountdown()">Start Countdown</button>
<div id="countdown">00:00:00</div>
</div>
<!-- Audio Element: Adjust the path to your audio file -->
<audio id="alarmAudio" src="assets/media/night-whisper.mp3" preload="auto"></audio>
/* CSS */
body {
font-family: Arial, sans-serif;
text-align: center;
margin: 50px;
}
.container {
max-width: 350px;
margin: 0 auto;
}
input[type="number"] {
padding: 10px;
width: 30%;
font-size: 16px;
box-sizing: border-box;
margin: 5px 1%;
}
button {
padding: 10px;
margin-top: 10px;
font-size: 16px;
cursor: pointer;
width: 100%;
}
#countdown {
font-size: 48px;
margin-top: 20px;
font-weight: bold;
}
// JavaScript
let countdownInterval;
function startCountdown() {
clearInterval(countdownInterval);
// Read input values and convert to integers
const hours = parseInt(document.getElementById("hoursInput").value, 10) || 0;
const minutes = parseInt(document.getElementById("minutesInput").value, 10) || 0;
const seconds = parseInt(document.getElementById("secondsInput").value, 10) || 0;
// Calculate total time in seconds
let totalSeconds = hours * 3600 + minutes * 60 + seconds;
if (totalSeconds <= 0) {
alert("Please enter a valid time.");
return;
}
updateDisplay(totalSeconds);
countdownInterval = setInterval(() => {
totalSeconds--;
if (totalSeconds < 0) {
clearInterval(countdownInterval);
// Automatically play audio when the time is up
document.getElementById("alarmAudio").play();
// Set countdown display to 00:00:00
document.getElementById("countdown").textContent = "00:00:00";
return;
}
updateDisplay(totalSeconds);
}, 1000);
}
function updateDisplay(totalSeconds) {
const hours = Math.floor(totalSeconds / 3600);
const remainder = totalSeconds % 3600;
const minutes = Math.floor(remainder / 60);
const secs = remainder % 60;
// Formatting: always two digits
document.getElementById("countdown").textContent =
(hours < 10 ? "0" : "") + hours + ":" +
(minutes < 10 ? "0" : "") + minutes + ":" +
(secs < 10 ? "0" : "") + secs;
}
Mouse Animation
Track, glow, transform – turn mouse movement into an experience!
<!-- HTML -->
<body>
<!-- Custom Cursor -->
<div id="cursor">
</div>
</body>
</html>
/* CSS */
/* Hide default cursor */
body {
cursor: none;
margin: 0;
height: 100vh;
background: #111;
overflow: hidden;
}
/* Custom cursor: circle */
#cursor {
position: fixed;
top: 0;
left: 0;
width: 20px;
height: 20px;
border: 2px solid #ff00ee;
border-radius: 50%;
pointer-events: none;
transform: translate(-50%, -50%);
z-index: 1000;
}
/* Particles that follow the cursor */
.particle {
position: fixed;
width: 6px;
height: 6px;
background: #c83dff;
border-radius: 50%;
pointer-events: none;
z-index: 999;
opacity: 1;
animation: particleAnim 0.8s ease-out forwards;
}
/* Animation for the particles */
@keyframes particleAnim {
0% {
transform: translate(0, 0) scale(1);
opacity: 1;
}
100% {
transform: translate(var(--tx), var(--ty)) scale(0);
opacity: 0;
}
}
// JavaScript
const cursor = document.getElementById('cursor');
document.addEventListener('mousemove', e => {
// Set the position of the custom cursor
cursor.style.top = e.clientY + 'px';
cursor.style.left = e.clientX + 'px';
// Create a particle at the cursor position
const particle = document.createElement('div');
particle.className = 'particle';
particle.style.top = e.clientY + 'px';
particle.style.left = e.clientX + 'px';
// Generate random values for the animation (direction and distance)
const angle = Math.random() * 2 * Math.PI;
const distance = Math.random() * 30 + 10; // between 10 and 40px
const tx = Math.cos(angle) * distance + "px";
const ty = Math.sin(angle) * distance + "px";
particle.style.setProperty('--tx', tx);
particle.style.setProperty('--ty', ty);
document.body.appendChild(particle);
// Remove the particle after the animation ends (0.8s)
setTimeout(() => {
particle.remove();
}, 800);
});