Website overhaul

This commit is contained in:
sageTheDM 2025-09-21 23:37:16 +02:00
parent cd401ee5b6
commit 4cb566828a
71 changed files with 1999 additions and 4058 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
node_modules/

View file

@ -1,2 +0,0 @@
# pages

View file

@ -1,61 +0,0 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
/*
* InterstellarDevelopment website
* Copyright (C) 2024 interstellar_development
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
document.addEventListener("DOMContentLoaded", () => {
const menu = document.querySelector(".menu");
const burgerMenu = document.querySelector(".burger-menu");
if (!menu || !burgerMenu) {
console.warn(
"Menu or burger menu element not found. Ensure they exist in the DOM."
);
return;
}
// Toggle the menu visibility
function toggleMenu() {
menu.classList.toggle("active");
if (menu.classList.contains("active")) {
// Add click listener to close menu when clicking outside
document.addEventListener("click", closeMenu);
} else {
// Remove the click listener when menu is closed
document.removeEventListener("click", closeMenu);
}
}
// Close the menu if clicking outside of it
function closeMenu(event) {
if (
!menu.contains(event.target) &&
!event.target.classList.contains("burger-menu")
) {
menu.classList.remove("active");
document.removeEventListener("click", closeMenu);
}
}
// Attach click event to the burger menu button
burgerMenu.addEventListener("click", (event) => {
event.stopPropagation(); // Prevent click from immediately triggering closeMenu
toggleMenu();
});
});
// @license-end

View file

@ -1,6 +0,0 @@
This favicon was generated using the following graphics from Twitter Twemoji:
- Graphics Title: 1f680.svg
- Graphics Author: Copyright 2020 Twitter, Inc and other contributors (https://github.com/twitter/twemoji)
- Graphics Source: https://github.com/twitter/twemoji/blob/master/assets/svg/1f680.svg
- Graphics License: CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 751 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1 +0,0 @@
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}

View file

@ -1,68 +0,0 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
/*
* interstellar_development website
* Copyright (C) 2024 interstellar_development
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
class Footer extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.innerHTML = `
<center>
<footer>
<div class="footer-content">
<p>2024 Interstellar Development</p>
<!-- Hidden Button -->
<button class="secret-button">👀</button>
</div>
</footer>
</center>
`;
// Add event listener for button click
this.querySelector(".secret-button").addEventListener("click", () => {
window.open("secret/index.html", "_blank");
});
}
}
customElements.define("footer-component", Footer);
// CSS for the hidden button
const style = document.createElement("style");
style.textContent = `
.secret-button {
display: none;
position: absolute;
bottom: 10px;
right: 10px;
background-color: transparent;
border: none;
font-size: 24px;
cursor: pointer;
}
.footer-content:hover .secret-button {
display: block;
}
`;
document.head.appendChild(style);
// @license-end

View file

@ -1,46 +0,0 @@
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-3.0
/*
* interstellar_development website
* Copyright (C) 2024 interstellar_development
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
class Header extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
this.innerHTML = `
<header>
<div class="header-content">
<div><a href="index.html" class="project-name">Interstellar Development</a></div>
<button class="burger-menu" onclick="toggleMenu()"></button>
</div>
</header>
<div class="div-menu">
<ul class="menu">
<li><a href="index.html#project">Our Projects</a></li>
<li><a href="index.html#cards">Our Team</a></li>
<li><a href="index.html#about">About us</a></li>
<li><a href="index.html#vision">Our Vision</a></li>
</ul>
</div>
`;
}
}
customElements.define("header-component", Header);
// @license-end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 545 KiB

View file

@ -1,233 +1,480 @@
<!--
interstellar development website
Copyright (C) 2024 interstellar_development
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-->
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="dropdown.js" type="text/javascript" defer></script> <title>Interstellar Development | Free and Open Source Software</title>
<script src="header.js" type="text/javascript" defer></script> <meta
<script src="footer.js" type="text/javascript" defer></script> name="description"
<link rel="stylesheet" href="styles.css" /> content="We develop high-quality free and open source software, with a focus on gaming solutions that respect user freedom."
<link
rel="apple-touch-icon"
sizes="180x180"
href="favicon_io/apple-touch-icon.png"
/> />
<!-- Font Awesome -->
<link <link
rel="icon" rel="stylesheet"
type="image/png" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
sizes="32x32"
href="favicon_io/favicon-32x32.png"
/> />
<!-- Google Fonts -->
<link <link
rel="icon" href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap"
type="image/png" rel="stylesheet"
sizes="16x16"
href="favicon_io/favicon-16x16.png"
/> />
<link rel="manifest" href="favicon_io/site.webmanifest" /> <!-- Main CSS -->
<title>Interstellar Development</title> <link rel="stylesheet" href="src/styles/styles.css" />
</head> </head>
<body> <body>
<!-- Custom header component --> <!-- Animated background -->
<header-component></header-component> <div class="animated-bg"></div>
<div class="stars" id="stars"></div>
<article> <!-- Navigation -->
<section id="project"> <nav id="navigation">
<h1>Our Projects</h1> <div class="nav-container">
<div class="logo">Interstellar Development</div>
<h2>Our Games</h2> <button
<ul> class="mobile-menu-btn"
<a href="webGames/index.html" target="_blank" class="listElement"> id="mobile-menu-btn"
<li>Web game collection</li> aria-label="Toggle navigation"
</a> >
<i class="fas fa-bars"></i>
</button>
<ul class="nav-links" id="nav-links">
<li><a href="#projects">Projects</a></li>
<li><a href="#team">Team</a></li>
<li><a href="#about">About</a></li>
<li><a href="#vision">Vision</a></li>
<li><a href="#contact">Contact</a></li>
</ul> </ul>
</div>
</nav>
<ul> <main>
<li> <!-- Hero Section -->
<p>Previously we had more unfinished Games listed here.</p> <section class="hero">
<div class="container">
<div class="hero-content">
<h1>
Advancing <span class="highlight">Free Software</span> Development
</h1>
<p> <p>
We decided against displaying them and giving people the We develop high-quality free and open source software solutions,
impression we are working on them currently. with a focus on gaming and applications that respect user freedom.
</p> </p>
<p>In the Future we will display the released games here</p> <div class="hero-buttons">
</li> <a href="#projects" class="btn btn-primary">
</ul> <i class="fas fa-rocket"></i>
View Our Projects
<h2>Our Other Projects</h2> </a>
<ul> <a href="#about" class="btn btn-secondary">
<a href="foss_alternatives/" target="_blank" class="listElement"> <i class="fas fa-info-circle"></i>
<li>FOSS Alternatives</li> Learn More
</a> </a>
<a href="react/" target="_blank" class="listElement"> </div>
<li>React</li> </div>
</a>
</ul>
</section>
<!-- Cards section with team members -->
<h1>Our Team</h1>
<section class="cards" id="cards">
<div class="card">
<a
href="https://interstellardevelopment.org/code/Patrick_Pluto"
class="card-link"
target="_blank"
>
<img src="images/Patrick.png" alt="Patrick" />
<h3>Patrick_Pluto</h3>
<p>
The system administrator and our lead coder. He is the one you
will need to blame for bugs in the games
</p>
</a>
</div>
<div class="card">
<a
href="https://interstellardevelopment.org/code/sageTheDm"
class="card-link"
target="_blank"
>
<img src="images/sage.png" alt="Sage" />
<h3>sageTheDM</h3>
<p>
Our mostly competent web developer and secondary coder, if you
experience any bugs on the website or spelling mistake he is to
blame
</p>
</a>
</div>
<div class="card">
<a
href="https://interstellardevelopment.org/code/Patrick_Pluto"
class="card-link"
target="_blank"
>
<img src="images/nicolas.png" alt="Patrick" />
<h3>St. Nicolaus</h3>
<p>
Our game level and asset designer. He is responsible for all
assets in our FreeFTF game. So if an asset looks ugly be mad at
him. Also, we are not sure if he is human or just a drunk wizard
cat but one thing is very clear he is still a novice at his job.
</p>
</a>
</div> </div>
</section> </section>
<!-- About Us section --> <!-- Projects Section -->
<section id="about"> <section id="projects" class="section">
<h2>About Us</h2> <div class="container">
<p> <div class="section-header">
Welcome to Interstellar Development! We are a small, passionate <h2 class="section-title">Our Projects</h2>
international team dedicated to transforming the programming world <p class="section-subtitle">
into a free-and-open-source future. Our diverse backgrounds and High-quality free software solutions built with passion and
experiences fuel our commitment to creating free and open-source dedication
software, particularly in the realm of gaming. </p>
</p> </div>
<p>
Our journey began with a shared vision: to better organize our efforts <div class="project-category">
in making free and open-source games more efficient and accessible. We <h3 class="category-title">Gaming Projects</h3>
recognized that many current free software games are either lacking in <div class="projects-grid">
quality or simply do not exist. This realization inspired us to focus <div class="project-card">
on developing games that are unplayable on GNU/Linux and FreeBSD <div class="project-icon">
systems, as well as creating free software alternatives for those in <i class="fas fa-crosshairs"></i>
need. </div>
</p> <h3>Chromania</h3>
<p> <p>
At Interstellar Development, we believe that true freedom for computer A 2D jump-and-run game where players must restore color to the
users can only be achieved through the use of free software. Thats world. Developed with our assistance. <br />
why we are committed to licensing all of our projects under copyleft <span class="project-status development">In Development</span>
free and open-source software licenses, ensuring that our games remain </p>
free for everyone to enjoy, forever. </div>
</p>
<p> <div class="project-card">
While we are not currently accepting donations, we welcome your <div class="project-icon">
support in the form of feedback and suggestions for improvements. If <i class="fas fa-crosshairs"></i>
you wish to contribute financially, we encourage you to donate to the </div>
Free Software Foundation, as without them, we would have never started <h3>The tale of the Free</h3>
this. <p>
</p> A 2.5D RPG where the protagonist journeys through the world,
<p> gaining friends and allies to overthrow a corrupt government
Join us as we strive to create a vibrant community around free branch. <br />
software and gaming. Together, we can make a difference and pave the <span class="project-status development">In Planning</span>
way for a free future! </p>
</p> </div>
</div>
</div>
<div class="project-category">
<h3 class="category-title">Software Solutions</h3>
<div class="projects-grid">
<div class="project-card">
<div class="project-icon">
<i class="fas fa-code"></i>
</div>
<h3>FOSS Alternatives</h3>
<p>
We maintain a curated list of free software alternatives to
proprietary applications, focusing on quality and user
freedom.
</p>
<span class="project-status active">Ongoing</span>
</div>
</div>
</div>
</div>
</section> </section>
<section id="vision"> <!-- Team Section -->
<h2>Our Vision</h2> <section id="team" class="section">
<h2>Interstellar Development: Free Software is Our Passion</h2> <div class="container">
<p> <div class="section-header">
At Interstellar Development, we embarked on this journey to create a <h2 class="section-title">Our Team</h2>
more organized and efficient approach to developing free and <p class="section-subtitle">
open-source software, with a particular focus on gaming. We recognized A small but dedicated international team committed to free
a significant gap in the availability and quality of free software software
games, which often fail to meet the expectations of users or simply do </p>
not exist. Our mission is to fill this void and elevate the standards </div>
of free gaming experiences.
</p>
<p>
Our primary goal is to target games that are currently unplayable on
GNU/Linux and FreeBSD systems. We aim to develop high-quality
alternatives that not only provide enjoyable gameplay but also adhere
to the principles of free software. Additionally, we are committed to
identifying and addressing other areas within the software ecosystem
that lack free alternatives, ensuring that users have access to a
diverse range of tools and applications that respect their freedom.
</p>
<p>
At Interstellar Development, we firmly believe that the path to true
freedom for computer users lies in the adoption and promotion of free
software. To this end, we are dedicated to licensing all of our
projects under copyleft free and open-source software licenses. This
commitment ensures that our games and software remain free for
everyone to play, modify, and share, fostering a culture of
collaboration and innovation within the community.
</p>
<p>
We understand that community involvement is crucial to our success.
While we are not currently accepting donations, we invite you to
support us by providing feedback, reporting issues, and suggesting
improvements. Your insights are invaluable in helping us refine our
projects and enhance the user experience.
</p>
<p>
If you feel compelled to contribute financially, we encourage you to
consider donating to the Free Software Foundation. Their unwavering
support and advocacy for free software principles have been
instrumental in our journey, and your contributions to them help
sustain the broader movement that enables us to create these games.
</p>
<p>
Together, we can build a vibrant community around free software and
gaming, paving the way for a future where everyone has access to
high-quality, open-source alternatives. Join us in our mission to make
a difference and champion the cause of free software for all!
</p>
</section>
</article>
<!-- Custom footer component --> <div class="team-grid">
<footer-component></footer-component> <div class="team-member">
<div class="member-avatar">
<i class="fas fa-server"></i>
</div>
<h3>Patrick</h3>
<div class="team-role">
Lead Programmer & System Administrator
</div>
<p>
Patrick focuses on backend development and system
administration, managing our infrastructure and core application
logic with expertise in server-side technologies and DevOps.
</p>
</div>
<div class="team-member">
<div class="member-avatar">
<i class="fas fa-palette"></i>
</div>
<h3>Sage</h3>
<div class="team-role">Frontend Developer & Communications</div>
<p>
Sage focuses on frontend development and is in charge of
communication and UI/UX design, ensuring our projects have
intuitive interfaces and excellent user experiences.
</p>
</div>
</div>
</div>
</section>
<!-- About Section -->
<section id="about" class="section">
<div class="container">
<div class="section-header">
<h2 class="section-title">About Us</h2>
</div>
<div class="about-content">
<p>
Interstellar Development is a small international team dedicated
to advancing free and open source software. Our diverse
backgrounds and shared commitment to user freedom drive our
development philosophy.
</p>
<p>
We began with a vision to create high-quality free software,
particularly in gaming where such options are often limited. We
recognized that many free software games either lack polish or
simply don't exist, inspiring us to focus on this underserved
area.
</p>
<p>
At Interstellar Development, we believe true digital freedom can
only be achieved through free software. All our projects are
released under copyleft licenses, ensuring they remain free for
everyone to use, modify, and distribute.
</p>
<p>
While we don't currently accept donations, we welcome feedback and
suggestions. If you wish to support the free software movement, we
encourage donations to the Free Software Foundation, whose work
continues to inspire our journey.
</p>
</div>
</div>
</section>
<!-- Vision Section -->
<section id="vision" class="section">
<div class="container">
<div class="section-header">
<h2 class="section-title">Our Vision</h2>
</div>
<div class="vision-content">
<div class="vision-text">
<p>
Our mission is to create high-quality free software
alternatives, particularly for games that are unavailable on
free operating systems like GNU/Linux and FreeBSD. We aim to
address gaps in the software ecosystem where free alternatives
are lacking.
</p>
</div>
<div class="principles-grid">
<div class="principle-card">
<div class="principle-icon">
<i class="fas fa-unlock"></i>
</div>
<h4>Software Freedom</h4>
<p>
All our projects are released under copyleft licenses to
ensure user freedoms are protected and preserved.
</p>
</div>
<div class="principle-card">
<div class="principle-icon">
<i class="fas fa-users"></i>
</div>
<h4>Community Collaboration</h4>
<p>
We believe in building software with and for the community,
welcoming contributions and feedback.
</p>
</div>
<div class="principle-card">
<div class="principle-icon">
<i class="fas fa-star"></i>
</div>
<h4>Quality Standards</h4>
<p>
We strive to create software that matches or exceeds the
quality of proprietary alternatives.
</p>
</div>
</div>
</div>
</div>
</section>
<!-- Contact Section -->
<section id="contact" class="section">
<div class="container">
<div class="section-header">
<h2 class="section-title">Get In Touch</h2>
<p class="section-subtitle">
Have questions about our projects or want to contribute? We'd love
to hear from you.
</p>
</div>
<div class="contact-container">
<div class="contact-info">
<div class="contact-methods">
<div class="contact-item">
<div class="contact-icon">
<i class="fas fa-envelope"></i>
</div>
<div class="contact-details">
<h4>Email</h4>
<a href="mailto:info@interstellardevelopment.org"
>info@interstellardevelopment.org</a
>
</div>
</div>
<div class="contact-item">
<div class="contact-icon">
<i class="fas fa-code-branch"></i>
</div>
<div class="contact-details">
<h4>Source Code</h4>
<a
href="https://interstellardevelopment.org/code/interstellar_development"
target="_blank"
>View Our Projects</a
>
</div>
</div>
</div>
</div>
<form class="contact-form" id="contact-form">
<div class="form-group">
<label for="name">Your Name</label>
<input type="text" id="name" name="name" required />
</div>
<div class="form-group">
<label for="email">Email Address</label>
<input type="email" id="email" name="email" required />
</div>
<div class="form-group">
<label for="subject">Subject</label>
<select id="subject" name="subject" required>
<option value="">Select a subject</option>
<option value="contribution">Project Contribution</option>
<option value="feedback">Feedback</option>
<option value="inquiry">General Inquiry</option>
<option value="bug">Bug Report</option>
<option value="other">Other</option>
</select>
</div>
<div class="form-group">
<label for="message">Message</label>
<textarea
id="message"
name="message"
rows="5"
required
></textarea>
</div>
<button type="submit" class="btn btn-primary">
<i class="fas fa-paper-plane"></i>
Send Message
</button>
</form>
</div>
</div>
</section>
<!-- Footer -->
<footer class="footer">
<div class="container">
<div class="footer-content">
<div class="footer-brand">
<div class="logo">Interstellar Development</div>
<p>
Developing free and open source software with a focus on user
freedom and quality.
</p>
<div class="footer-social">
<a
href="https://interstellardevelopment.org/code/interstellar_development"
class="social-link"
target="_blank"
aria-label="Source Code"
>
<i class="fas fa-code-branch"></i>
</a>
<a href="#" class="social-link" aria-label="Discord">
<i class="fab fa-discord"></i>
</a>
<a href="#" class="social-link" aria-label="Mastodon">
<i class="fab fa-mastodon"></i>
</a>
</div>
</div>
<div class="footer-links">
<h4>Navigation</h4>
<ul>
<li><a href="#projects">Projects</a></li>
<li><a href="#team">Team</a></li>
<li><a href="#about">About</a></li>
<li><a href="#vision">Vision</a></li>
<li><a href="#contact">Contact</a></li>
</ul>
</div>
<div class="footer-links">
<h4>Projects</h4>
<ul>
<li>
<a
href="https://interstellardevelopment.org/code/interstellar_development"
target="_blank"
>Web Game Collection</a
>
</li>
<li>
<a
href="https://interstellardevelopment.org/code/interstellar_development"
target="_blank"
>FreeFTF Game</a
>
</li>
<li>
<a
href="https://interstellardevelopment.org/code/interstellar_development"
target="_blank"
>React Components</a
>
</li>
<li>
<a
href="https://interstellardevelopment.org/code/interstellar_development"
target="_blank"
>FOSS Alternatives</a
>
</li>
</ul>
</div>
<div class="footer-links">
<h4>Resources</h4>
<ul>
<li>
<a href="https://www.fsf.org/" target="_blank"
>Free Software Foundation</a
>
</li>
<li>
<a href="https://www.gnu.org/" target="_blank">GNU Project</a>
</li>
<li>
<a
href="https://interstellardevelopment.org/code/interstellar_development"
target="_blank"
>Source Code</a
>
</li>
<li>
<a href="mailto:info@interstellardevelopment.org"
>Contact Us</a
>
</li>
</ul>
</div>
</div>
<div class="footer-bottom">
<div class="footer-bottom-content">
<p>&copy; 2025 Interstellar Development. All rights reserved.</p>
<div class="footer-badges">
<span class="badge">
<i class="fas fa-heart"></i>
Committed to Free Software
</span>
</div>
</div>
</div>
</div>
</footer>
</main>
</body> </body>
</html> </html>

46
package-lock.json generated Normal file
View file

@ -0,0 +1,46 @@
{
"name": "photofuel.tech",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "photofuel.tech",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"bootstrap": "^5.3.7"
}
},
"node_modules/@popperjs/core": {
"version": "2.11.8",
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
"license": "MIT",
"peer": true,
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/popperjs"
}
},
"node_modules/bootstrap": {
"version": "5.3.7",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.7.tgz",
"integrity": "sha512-7KgiD8UHjfcPBHEpDNg+zGz8L3LqR3GVwqZiBRFX04a1BCArZOz1r2kjly2HQ0WokqTO0v1nF+QAt8dsW4lKlw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/twbs"
},
{
"type": "opencollective",
"url": "https://opencollective.com/bootstrap"
}
],
"license": "MIT",
"peerDependencies": {
"@popperjs/core": "^2.11.8"
}
}
}
}

18
package.json Normal file
View file

@ -0,0 +1,18 @@
{
"name": "photofuel.tech",
"version": "1.0.0",
"description": "",
"main": "index.html",
"scripts": {
"start": "http-server"
},
"repository": {
"type": "git",
"url": "ssh://git@interstellardevelopment.org/sageTheDm/KSSM293.git"
},
"author": "",
"license": "ISC",
"dependencies": {
"bootstrap": "^5.3.7"
}
}

View file

@ -1,47 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Game Landing Page</title>
<link rel="stylesheet" href="styles.css" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="../../favicon_io/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="../../favicon_io/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="../../favicon_io/favicon-16x16.png"
/>
<link rel="manifest" href="../../favicon_io/site.webmanifest" />
</head>
<body>
<div class="landing-page">
<div class="game-background">
<!-- Game is embedded or shown as background -->
<canvas id="gameCanvas"></canvas>
</div>
<div class="content">
<h1>Welcome to the Asteroid Game!</h1>
<p>
In this game, you control a spaceship that shoots at asteroids to
avoid destruction and collect items for power-ups.
</p>
<p>Your goal is to survive as long as possible while scoring points!</p>
<button onclick="window.location.href='secret.html'">Play Game</button>
</div>
</div>
<script src="app.js"></script>
</body>
</html>

View file

@ -1,414 +0,0 @@
"use strict";
// Canvas setup
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
const targetFPS = 60;
const targetFrameTime = 1000 / targetFPS;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
let lastFrameTime = performance.now();
// Game elements
const player = {
x: canvas.width / 2,
y: canvas.height - 60,
width: 40,
height: 40,
color: "white",
speed: 5,
dx: 0,
};
let bullets = [];
let asteroids = [];
let items = [];
let score = 0;
let totalBulletsFired = 0;
let isGameOver = false;
let lastBulletTime = 0;
let ammo = 100; // Ammo counter
// Difficulty control
let asteroidSpawnInterval = 800; // Faster spawn rate
let asteroidSpeedMultiplier = 1.5; // Faster asteroids from the start
let difficultyIncreaseRate = 0.2; // Faster scaling every 10 seconds
// Controls
let canShoot = true; // Flag to control shooting
let rapidFireActive = false;
let shotgunActive = false;
let rainbowActive = false;
let lastShotgunTime = 0;
// Controls for sphere effects
let blueSphereCooldown = 0;
let yellowSphereCooldown = 0;
let greenSphereCooldown = 0;
let rainbowSphereCooldown = 0;
// Sphere types
const sphereTypes = ["blue", "yellow", "green", "rainbow"];
/// Control for left button press and release
function btnMoveLeft(isPressed) {
if (isPressed) {
player.dx = -player.speed; // Start moving left
} else {
player.dx = 0; // Stop moving when button is released
}
}
// Control for shoot button click (simulates spacebar press)
function btnShoot() {
if (canShoot && !isGameOver) {
shootBullet();
canShoot = false; // Prevent shooting until the button is "released"
}
}
// Control for right button press and release
function btnMoveRight(isPressed) {
if (isPressed) {
player.dx = player.speed; // Start moving right
} else {
player.dx = 0; // Stop moving when button is released
}
}
document.getElementById("shootBtn").addEventListener("mouseup", () => {
canShoot = true; // Allow shooting again when button is released
});
window.addEventListener("keydown", (e) => {
if (e.key === "ArrowLeft" || e.key === "a") player.dx = -player.speed;
if (e.key === "ArrowRight" || e.key === "d") player.dx = player.speed;
// Shoot only if it's not a hold, and we can shoot
if (e.key === " " && canShoot && !isGameOver) {
shootBullet();
canShoot = false; // Prevent shooting until the key is released
}
if (e.key === "r" && isGameOver) restartGame();
});
window.addEventListener("keyup", (e) => {
// Stop moving when either the arrow keys or the 'a'/'d' keys are released
if (
e.key === "ArrowLeft" ||
e.key === "ArrowRight" ||
e.key === "a" ||
e.key === "d"
) {
player.dx = 0;
}
// Allow shooting again when the space key is released
if (e.key === " ") {
canShoot = true;
}
});
// Bullet mechanics with cooldown
function shootBullet() {
const now = Date.now();
if (now - lastBulletTime < 100) return; // Enforce cooldown of 0.1 seconds
if (ammo <= 0) return; // Prevent shooting if ammo is empty
lastBulletTime = now;
ammo--; // Decrease ammo
totalBulletsFired++; // Increment total bullets fired
if (rapidFireActive) {
// If rapid fire is active, fire bullets continuously with a short delay
for (let i = 0; i < 3; i++) {
setTimeout(() => {
bullets.push({
x: player.x + player.width / 2 - 2.5,
y: player.y,
width: 5,
height: 10,
color: "yellow",
speed: 7,
});
}, i * 50); // Fire bullets with 50ms delay between shots
}
} else if (shotgunActive) {
// Shotgun effect, firing 3 bullets with a spread
for (let i = -1; i <= 1; i++) {
bullets.push({
x: player.x + player.width / 2 - 2.5,
y: player.y,
width: 5,
height: 10,
color: "yellow",
speed: 7,
angle: i * 10, // Spray the bullets at different angles
});
}
} else {
// Normal bullet
bullets.push({
x: player.x + player.width / 2 - 2.5,
y: player.y,
width: 5,
height: 10,
color: "yellow",
speed: 7,
});
}
}
// Generate random color
function getRandomColor() {
const colors = ["red", "blue", "green", "orange", "purple", "pink"];
return colors[Math.floor(Math.random() * colors.length)];
}
// Asteroid mechanics
function createAsteroid() {
const size = Math.random() * 40 + 30; // Bigger asteroids (min: 30, max: 70)
asteroids.push({
x: Math.random() * canvas.width,
y: -size,
width: size,
height: size,
color: getRandomColor(),
speed: (Math.random() * 3 + 2) * asteroidSpeedMultiplier, // Faster initial speed
});
}
// Item mechanics
function createItem() {
const randomType =
sphereTypes[Math.floor(Math.random() * sphereTypes.length)];
const size = 30;
const x = Math.random() * canvas.width;
items.push({
x: x,
y: -size,
width: size,
height: size,
type: randomType,
color:
randomType === "blue"
? "blue"
: randomType === "yellow"
? "yellow"
: randomType === "green"
? "green"
: "rainbow",
speed: 3,
});
}
// Update game elements
function updatePlayer() {
player.x += player.dx;
if (player.x < 0) player.x = 0;
if (player.x + player.width > canvas.width)
player.x = canvas.width - player.width;
}
function updateBullets() {
bullets.forEach((bullet, index) => {
bullet.y -= bullet.speed;
if (bullet.y + bullet.height < 0) bullets.splice(index, 1);
});
}
function updateAsteroids() {
asteroids.forEach((asteroid, index) => {
asteroid.y += asteroid.speed;
if (asteroid.y > canvas.height) asteroids.splice(index, 1);
});
}
function updateItems() {
items.forEach((item, index) => {
item.y += item.speed;
if (item.y > canvas.height) items.splice(index, 1);
// Check if player collects the item
if (
player.x < item.x + item.width &&
player.x + player.width > item.x &&
player.y < item.y + item.height &&
player.y + player.height > item.y
) {
applyItemEffect(item.type);
items.splice(index, 1); // Remove the item after it is collected
}
});
}
function applyItemEffect(type) {
let points = Math.floor(Math.random() * 5) + 1; // Random points between 1 and 5
if (type === "blue") {
rapidFireActive = true;
setTimeout(() => (rapidFireActive = false), 15000); // 15 seconds of rapid fire
} else if (type === "yellow") {
shotgunActive = true;
setTimeout(() => (shotgunActive = false), 30000); // 30 seconds of shotgun
} else if (type === "green") {
ammo = 100; // Refill ammo
} else if (type === "rainbow") {
rapidFireActive = true;
shotgunActive = true;
setTimeout(() => {
rapidFireActive = false;
shotgunActive = false;
}, 15000); // 15 seconds with all effects
}
score += points; // Add points when an item is collected
}
// Collision detection
function checkCollisions() {
bullets.forEach((bullet, bIndex) => {
asteroids.forEach((asteroid, aIndex) => {
if (
bullet.x < asteroid.x + asteroid.width &&
bullet.x + bullet.width > asteroid.x &&
bullet.y < asteroid.y + asteroid.height &&
bullet.y + bullet.height > asteroid.y
) {
bullets.splice(bIndex, 1);
asteroids.splice(aIndex, 1);
score += Math.floor(Math.random() * 5) + 1; // Add points when an asteroid is destroyed
// Visual feedback for destroyed asteroid
createExplosion(asteroid.x, asteroid.y);
}
});
});
asteroids.forEach((asteroid) => {
if (
player.x < asteroid.x + asteroid.width &&
player.x + player.width > asteroid.x &&
player.y < asteroid.y + asteroid.height &&
player.y + player.height > asteroid.y
) {
isGameOver = true;
}
});
}
// Explosion effect
function createExplosion(x, y) {
ctx.fillStyle = "yellow";
ctx.beginPath();
ctx.arc(x, y, 20, 0, Math.PI * 2);
ctx.fill();
setTimeout(() => ctx.clearRect(x - 20, y - 20, 40, 40), 200); // Clear explosion after 200ms
}
// Draw elements
function drawPlayer() {
ctx.fillStyle = player.color;
ctx.fillRect(player.x, player.y, player.width, player.height);
}
function drawBullets() {
bullets.forEach((bullet) => {
ctx.fillStyle = bullet.color;
ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
});
}
function drawAsteroids() {
asteroids.forEach((asteroid) => {
ctx.fillStyle = asteroid.color;
ctx.fillRect(asteroid.x, asteroid.y, asteroid.width, asteroid.height);
});
}
function drawItems() {
items.forEach((item) => {
ctx.fillStyle = item.color;
ctx.beginPath();
ctx.arc(
item.x + item.width / 2,
item.y + item.height / 2,
item.width / 2,
0,
Math.PI * 2
);
ctx.fill();
});
}
function drawScore() {
ctx.fillStyle = "white";
ctx.font = "24px Arial";
ctx.fillText(`Score: ${score}`, 20, 40); // Score at top-left corner
}
function drawAmmo() {
ctx.fillStyle = "white";
ctx.font = "24px Arial";
ctx.fillText(`Ammo: ${ammo}`, 20, 70); // Ammo at top-left corner
}
function drawGameOver() {
if (isGameOver) {
ctx.fillStyle = "white";
ctx.font = "40px Arial";
ctx.textAlign = "center";
ctx.fillText("Game Over!", canvas.width / 2, canvas.height / 2 - 40);
ctx.font = "24px Arial";
ctx.fillText(`Total Score: ${score}`, canvas.width / 2, canvas.height / 2);
ctx.fillText(
`Bullets Fired: ${totalBulletsFired}`,
canvas.width / 2,
canvas.height / 2 + 40
);
ctx.fillText(
'Press "R" to Restart',
canvas.width / 2,
canvas.height / 2 + 80
);
}
}
// Restart game
function restartGame() {
window.location.reload();
}
// Main game loop
function gameLoop() {
const currentTime = performance.now();
const elapsedTime = currentTime - lastFrameTime;
if (elapsedTime >= targetFrameTime) {
lastFrameTime = currentTime - (elapsedTime % targetFrameTime);
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (!isGameOver) {
updatePlayer();
updateBullets();
updateAsteroids();
updateItems();
checkCollisions();
}
drawPlayer();
drawBullets();
drawAsteroids();
drawItems();
drawScore();
drawAmmo();
drawGameOver();
if (!isGameOver) {
if (Math.random() < 0.01) createAsteroid(); // 1% chance every frame to spawn an asteroid
if (Math.random() < 0.005) createItem(); // 0.5% chance to spawn an item
}
}
requestAnimationFrame(gameLoop);
}
// Start game loop
requestAnimationFrame(gameLoop);

View file

@ -1,41 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Asteroid Shooter</title>
<link rel="stylesheet" href="style.css" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="../../favicon_io/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="../../favicon_io/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="../../favicon_io/favicon-16x16.png"
/>
<link rel="manifest" href="../../favicon_io/site.webmanifest" />
</head>
<body>
<canvas id="gameCanvas"></canvas>
<!-- Virtual buttons for mobile -->
<div class="controls">
<button id="leftBtn" class="control-btn">Left</button>
<button id="shootBtn" class="control-btn" onclick="btnShoot()">
Shoot
</button>
<button id="rightBtn" class="control-btn">Right</button>
</div>
<script src="game.js"></script>
</body>
</html>

View file

@ -1,43 +0,0 @@
body {
margin: 0;
overflow: hidden;
}
canvas {
display: block;
background: black;
width: 100%;
height: 100%;
}
.controls {
display: none;
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
justify-content: space-between;
width: 80%;
}
.control-btn {
display: none;
padding: 10px;
font-size: 18px;
background-color: rgba(0, 0, 0, 0.6);
color: white;
border: 1px solid #fff;
border-radius: 5px;
cursor: pointer;
flex-grow: 1;
margin: 0 5px;
}
@media (max-width: 600px) {
.control-btn {
display: block;
font-size: 16px;
padding: 12px;
}
}

View file

@ -1,76 +0,0 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body,
html {
height: 100%;
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
background-color: #000;
color: white;
overflow: hidden;
}
.landing-page {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.game-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7); /* Dark overlay */
backdrop-filter: blur(8px); /* Apply blur effect to the background */
z-index: -1; /* Ensures it's in the background */
pointer-events: none; /* Prevent interaction with the blurred background */
}
.content {
text-align: center;
z-index: 1; /* Ensure content appears above the game background */
padding: 20px;
max-width: 600px; /* Limit the width of the content */
position: relative;
color: white;
backdrop-filter: blur(
8px
); /* Ensure content has some blur as well for contrast */
}
h1 {
font-size: 2rem;
margin-bottom: 20px;
}
p {
font-size: 1.2rem;
margin-bottom: 30px;
}
button {
padding: 12px 24px;
background-color: #ffcc00;
color: black;
border: none;
font-size: 18px;
cursor: pointer;
border-radius: 5px;
text-transform: uppercase;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #ff9900;
}

View file

@ -1,33 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Endless runner</title>
<link
rel="apple-touch-icon"
sizes="180x180"
href="../../favicon_io/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="../../favicon_io/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="../../favicon_io/favicon-16x16.png"
/>
<link rel="manifest" href="../../favicon_io/site.webmanifest" />
</head>
<body>
<div class="game-container">
<canvas id="gameCanvas"></canvas>
<button id="restartBtn" onclick="restartGame()">Restart</button>
</div>
<script src="script.js"></script>
</body>
</html>

View file

@ -1,90 +0,0 @@
import { useEffect, useRef, useState } from "react";
export default function EndlessRunner() {
const canvasRef = useRef(null);
const [running, setRunning] = useState(true);
const player = { x: 50, y: 150, width: 20, height: 20, dy: 0 };
const gravity = 0.5;
let obstacles = [];
let score = 0;
useEffect(() => {
const canvas = canvasRef.current;
const ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = 300;
function update() {
if (!running) return;
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Player physics
player.dy += gravity;
player.y += player.dy;
if (player.y > 150) {
player.y = 150;
player.dy = 0;
}
// Draw player
ctx.fillStyle = "blue";
ctx.fillRect(player.x, player.y, player.width, player.height);
// Obstacles
if (Math.random() < 0.02) {
obstacles.push({ x: canvas.width, y: 150, width: 20, height: 20 });
}
obstacles = obstacles.map((obstacle) => ({
...obstacle,
x: obstacle.x - 5,
}));
obstacles = obstacles.filter(
(obstacle) => obstacle.x + obstacle.width > 0
);
obstacles.forEach((obstacle) => {
ctx.fillStyle = "red";
ctx.fillRect(obstacle.x, obstacle.y, obstacle.width, obstacle.height);
// Collision detection
if (
player.x < obstacle.x + obstacle.width &&
player.x + player.width > obstacle.x &&
player.y < obstacle.y + obstacle.height &&
player.y + player.height > obstacle.y
) {
setRunning(false);
}
});
// Score
score++;
ctx.fillStyle = "black";
ctx.fillText("Score: " + score, 10, 20);
requestAnimationFrame(update);
}
update();
}, [running]);
function jump() {
if (player.y >= 150) {
player.dy = -10;
}
}
return (
<div className="flex flex-col items-center">
<canvas ref={canvasRef} className="border" onClick={jump}></canvas>
{!running && (
<button
onClick={() => window.location.reload()}
className="mt-4 bg-blue-500 text-white px-4 py-2 rounded"
>
Restart
</button>
)}
</div>
);
}

View file

@ -1,34 +0,0 @@
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f4f4f4;
}
.game-container {
position: relative;
text-align: center;
}
canvas {
border: 2px solid black;
background-color: white;
display: block;
}
#restartBtn {
margin-top: 10px;
padding: 10px 20px;
font-size: 16px;
background-color: #007bff;
color: white;
border: none;
cursor: pointer;
display: none;
}
#restartBtn:hover {
background-color: #0056b3;
}

View file

@ -1,404 +0,0 @@
"use strict";
// Canvas setup
const canvas = document.getElementById("gameCanvas");
const ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Game elements
const player = {
x: canvas.width / 2,
y: canvas.height - 60,
width: 40,
height: 40,
color: "white",
speed: 5,
dx: 0,
};
let bullets = [];
let asteroids = [];
let items = [];
let score = 0;
let totalBulletsFired = 0;
let isGameOver = false;
let lastBulletTime = 0;
let ammo = 100; // Ammo counter
// Difficulty control
let asteroidSpawnInterval = 800; // Faster spawn rate
let asteroidSpeedMultiplier = 1.5; // Faster asteroids from the start
let difficultyIncreaseRate = 0.2; // Faster scaling every 10 seconds
// Controls
let canShoot = true; // Flag to control shooting
let rapidFireActive = false;
let shotgunActive = false;
let rainbowActive = false;
let lastShotgunTime = 0;
// Controls for sphere effects
let blueSphereCooldown = 0;
let yellowSphereCooldown = 0;
let greenSphereCooldown = 0;
let rainbowSphereCooldown = 0;
// Sphere types
const sphereTypes = ["blue", "yellow", "green", "rainbow"];
/// Control for left button press and release
function btnMoveLeft(isPressed) {
if (isPressed) {
player.dx = -player.speed; // Start moving left
} else {
player.dx = 0; // Stop moving when button is released
}
}
// Control for shoot button click (simulates spacebar press)
function btnShoot() {
if (canShoot && !isGameOver) {
shootBullet();
canShoot = false; // Prevent shooting until the button is "released"
}
}
// Control for right button press and release
function btnMoveRight(isPressed) {
if (isPressed) {
player.dx = player.speed; // Start moving right
} else {
player.dx = 0; // Stop moving when button is released
}
}
document.getElementById("shootBtn").addEventListener("mouseup", () => {
canShoot = true; // Allow shooting again when button is released
});
window.addEventListener("keydown", (e) => {
if (e.key === "ArrowLeft" || e.key === "a") player.dx = -player.speed;
if (e.key === "ArrowRight" || e.key === "d") player.dx = player.speed;
// Shoot only if it's not a hold, and we can shoot
if (e.key === " " && canShoot && !isGameOver) {
shootBullet();
canShoot = false; // Prevent shooting until the key is released
}
if (e.key === "r" && isGameOver) restartGame();
});
window.addEventListener("keyup", (e) => {
// Stop moving when either the arrow keys or the 'a'/'d' keys are released
if (
e.key === "ArrowLeft" ||
e.key === "ArrowRight" ||
e.key === "a" ||
e.key === "d"
) {
player.dx = 0;
}
// Allow shooting again when the space key is released
if (e.key === " ") {
canShoot = true;
}
});
// Bullet mechanics with cooldown
function shootBullet() {
const now = Date.now();
if (now - lastBulletTime < 100) return; // Enforce cooldown of 0.1 seconds
if (ammo <= 0) return; // Prevent shooting if ammo is empty
lastBulletTime = now;
ammo--; // Decrease ammo
totalBulletsFired++; // Increment total bullets fired
if (rapidFireActive) {
// If rapid fire is active, fire bullets continuously with a short delay
for (let i = 0; i < 3; i++) {
setTimeout(() => {
bullets.push({
x: player.x + player.width / 2 - 2.5,
y: player.y,
width: 5,
height: 10,
color: "yellow",
speed: 7,
});
}, i * 50); // Fire bullets with 50ms delay between shots
}
} else if (shotgunActive) {
// Shotgun effect, firing 3 bullets with a spread
for (let i = -1; i <= 1; i++) {
bullets.push({
x: player.x + player.width / 2 - 2.5,
y: player.y,
width: 5,
height: 10,
color: "yellow",
speed: 7,
angle: i * 10, // Spray the bullets at different angles
});
}
} else {
// Normal bullet
bullets.push({
x: player.x + player.width / 2 - 2.5,
y: player.y,
width: 5,
height: 10,
color: "yellow",
speed: 7,
});
}
}
// Generate random color
function getRandomColor() {
const colors = ["red", "blue", "green", "orange", "purple", "pink"];
return colors[Math.floor(Math.random() * colors.length)];
}
// Asteroid mechanics
function createAsteroid() {
const size = Math.random() * 40 + 30; // Bigger asteroids (min: 30, max: 70)
asteroids.push({
x: Math.random() * canvas.width,
y: -size,
width: size,
height: size,
color: getRandomColor(),
speed: (Math.random() * 3 + 2) * asteroidSpeedMultiplier, // Faster initial speed
});
}
// Item mechanics
function createItem() {
const randomType =
sphereTypes[Math.floor(Math.random() * sphereTypes.length)];
const size = 30;
const x = Math.random() * canvas.width;
items.push({
x: x,
y: -size,
width: size,
height: size,
type: randomType,
color:
randomType === "blue"
? "blue"
: randomType === "yellow"
? "yellow"
: randomType === "green"
? "green"
: "rainbow",
speed: 3,
});
}
// Update game elements
function updatePlayer() {
player.x += player.dx;
if (player.x < 0) player.x = 0;
if (player.x + player.width > canvas.width)
player.x = canvas.width - player.width;
}
function updateBullets() {
bullets.forEach((bullet, index) => {
bullet.y -= bullet.speed;
if (bullet.y + bullet.height < 0) bullets.splice(index, 1);
});
}
function updateAsteroids() {
asteroids.forEach((asteroid, index) => {
asteroid.y += asteroid.speed;
if (asteroid.y > canvas.height) asteroids.splice(index, 1);
});
}
function updateItems() {
items.forEach((item, index) => {
item.y += item.speed;
if (item.y > canvas.height) items.splice(index, 1);
// Check if player collects the item
if (
player.x < item.x + item.width &&
player.x + player.width > item.x &&
player.y < item.y + item.height &&
player.y + player.height > item.y
) {
applyItemEffect(item.type);
items.splice(index, 1); // Remove the item after it is collected
}
});
}
function applyItemEffect(type) {
let points = Math.floor(Math.random() * 5) + 1; // Random points between 1 and 5
if (type === "blue") {
rapidFireActive = true;
setTimeout(() => (rapidFireActive = false), 15000); // 15 seconds of rapid fire
} else if (type === "yellow") {
shotgunActive = true;
setTimeout(() => (shotgunActive = false), 30000); // 30 seconds of shotgun
} else if (type === "green") {
ammo = 100; // Refill ammo
} else if (type === "rainbow") {
rapidFireActive = true;
shotgunActive = true;
setTimeout(() => {
rapidFireActive = false;
shotgunActive = false;
}, 15000); // 15 seconds with all effects
}
score += points; // Add points when an item is collected
}
// Collision detection
function checkCollisions() {
bullets.forEach((bullet, bIndex) => {
asteroids.forEach((asteroid, aIndex) => {
if (
bullet.x < asteroid.x + asteroid.width &&
bullet.x + bullet.width > asteroid.x &&
bullet.y < asteroid.y + asteroid.height &&
bullet.y + bullet.height > asteroid.y
) {
bullets.splice(bIndex, 1);
asteroids.splice(aIndex, 1);
score += Math.floor(Math.random() * 5) + 1; // Add points when an asteroid is destroyed
// Visual feedback for destroyed asteroid
createExplosion(asteroid.x, asteroid.y);
}
});
});
asteroids.forEach((asteroid) => {
if (
player.x < asteroid.x + asteroid.width &&
player.x + player.width > asteroid.x &&
player.y < asteroid.y + asteroid.height &&
player.y + player.height > asteroid.y
) {
isGameOver = true;
}
});
}
// Explosion effect
function createExplosion(x, y) {
ctx.fillStyle = "yellow";
ctx.beginPath();
ctx.arc(x, y, 20, 0, Math.PI * 2);
ctx.fill();
setTimeout(() => ctx.clearRect(x - 20, y - 20, 40, 40), 200); // Clear explosion after 200ms
}
// Draw elements
function drawPlayer() {
ctx.fillStyle = player.color;
ctx.fillRect(player.x, player.y, player.width, player.height);
}
function drawBullets() {
bullets.forEach((bullet) => {
ctx.fillStyle = bullet.color;
ctx.fillRect(bullet.x, bullet.y, bullet.width, bullet.height);
});
}
function drawAsteroids() {
asteroids.forEach((asteroid) => {
ctx.fillStyle = asteroid.color;
ctx.fillRect(asteroid.x, asteroid.y, asteroid.width, asteroid.height);
});
}
function drawItems() {
items.forEach((item) => {
ctx.fillStyle = item.color;
ctx.beginPath();
ctx.arc(
item.x + item.width / 2,
item.y + item.height / 2,
item.width / 2,
0,
Math.PI * 2
);
ctx.fill();
});
}
function drawScore() {
ctx.fillStyle = "white";
ctx.font = "24px Arial";
ctx.fillText(`Score: ${score}`, 20, 40); // Score at top-left corner
}
function drawAmmo() {
ctx.fillStyle = "white";
ctx.font = "24px Arial";
ctx.fillText(`Ammo: ${ammo}`, 20, 70); // Ammo at top-left corner
}
function drawGameOver() {
if (isGameOver) {
ctx.fillStyle = "white";
ctx.font = "40px Arial";
ctx.textAlign = "center";
ctx.fillText("Game Over!", canvas.width / 2, canvas.height / 2 - 40);
ctx.font = "24px Arial";
ctx.fillText(`Total Score: ${score}`, canvas.width / 2, canvas.height / 2);
ctx.fillText(
`Bullets Fired: ${totalBulletsFired}`,
canvas.width / 2,
canvas.height / 2 + 40
);
ctx.fillText(
'Press "R" to Restart',
canvas.width / 2,
canvas.height / 2 + 80
);
}
}
// Restart game
function restartGame() {
window.location.reload();
}
// Main game loop
function gameLoop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (!isGameOver) {
updatePlayer();
updateBullets();
updateAsteroids();
updateItems();
checkCollisions();
}
drawPlayer();
drawBullets();
drawAsteroids();
drawItems();
drawScore();
drawAmmo();
drawGameOver();
if (!isGameOver) {
if (Math.random() < 0.01) createAsteroid(); // 1% chance every frame to spawn an asteroid
if (Math.random() < 0.005) createItem(); // 0.5% chance to spawn an item
}
requestAnimationFrame(gameLoop);
}
// Start game loop
gameLoop();

View file

@ -1,65 +0,0 @@
"use strict";
const targetNum = Math.trunc(Math.random() * 20) + 1;
let highScore = Number(localStorage.getItem("highscore")) || 0;
let userGuess = 10; // Default guess
let currScore = 20;
const screenEl = document.querySelector(".screen");
const msgEl = document.querySelector(".message");
const guessInput = document.querySelector("#guess");
const scoreEl = document.querySelector(".score");
const highScoreEl = document.querySelector(".highScore");
const checkBtn = document.querySelector("#check");
const restartBtn = document.querySelector("#restart");
const incBtn = document.querySelector("#up");
const decBtn = document.querySelector("#down");
const setMsg = (msg) => (msgEl.textContent = msg);
const setScore = (score) =>
(scoreEl.textContent = `Score: ${(currScore = score)}`);
const setHighScore = () => {
highScoreEl.textContent = `Highscore: ${highScore}`;
localStorage.setItem("highscore", highScore);
};
const changeColor = (color) => (screenEl.style.backgroundColor = color);
checkBtn.addEventListener("click", () => {
userGuess = Number(guessInput.textContent);
if (!userGuess || userGuess < 1 || userGuess > 20) {
setMsg("Please enter a valid number between 1 and 20.");
} else if (userGuess === targetNum) {
highScore = Math.max(highScore, currScore);
setHighScore();
setMsg(
currScore !== 20 ? "Correct Number!" : "Are you sure you didn't cheat?"
);
changeColor(currScore !== 20 ? "#1ba100" : "#FFC300");
} else {
setMsg(userGuess > targetNum ? "Too High!" : "Too Low!");
if (currScore > 1) {
setScore(currScore - 1);
} else {
setScore(1);
setMsg("You lost the game!");
changeColor("#a10000");
}
}
});
restartBtn.addEventListener("click", () => location.reload());
incBtn.addEventListener(
"click",
() =>
(guessInput.textContent = Math.min(Number(guessInput.textContent) + 1, 20))
);
decBtn.addEventListener(
"click",
() =>
(guessInput.textContent = Math.max(Number(guessInput.textContent) - 1, 1))
);
guessInput.textContent = userGuess;
setMsg("Guess a number");
setScore(currScore);
setHighScore();

View file

@ -1,72 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Guess My Number</title>
<link rel="stylesheet" href="styles.css" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="../../favicon_io/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="../../favicon_io/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="../../favicon_io/favicon-16x16.png"
/>
<link rel="manifest" href="../../favicon_io/site.webmanifest" />
</head>
<body>
<div class="gameboy">
<!-- Game Boy Screen -->
<div class="screen">
<article class="game">
<h1>Guess My Number - Game</h1>
<p class="message"></p>
<div class="guess-display">
<span id="guess"></span>
</div>
<p class="score"></p>
<p class="highScore"></p>
<div class="description">
<h2>Description</h2>
<p>Guess a number between 1 and 20</p>
<p>A = check</p>
<p>B = Reload</p>
<p>▲ = increases guess by one</p>
<p>▼ = decreases guess by one</p>
</div>
</article>
</div>
<!-- Controls -->
<div class="controls">
<!-- D-Pad on the left -->
<div class="dpad">
<button class="dpad-btn up" id="up"></button>
<button class="dpad-btn left" id="left"></button>
<div class="dpad-center"></div>
<button class="dpad-btn right" id="right"></button>
<button class="dpad-btn down" id="down"></button>
</div>
<!-- A and B Buttons on the right -->
<div class="action-buttons">
<button class="btn" id="check">A</button>
<button class="btn" id="restart">B</button>
</div>
</div>
</div>
<script src="game.js"></script>
<script src="styles.js"></script>
</body>
</html>

View file

@ -1,189 +0,0 @@
/* Base Reset */
body,
html {
margin: 0;
padding: 0;
font-family: monospace;
background-color: #3a2d56;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
/* GameBoy Layout */
.gameboy {
background-color: #5f4c82; /* Game Boy Color purple shell */
width: 441px;
height: 735px;
border-radius: 20px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.6);
display: flex;
flex-direction: column;
align-items: center;
padding: 10px;
position: relative;
}
@media (max-width: 768px) {
.gameboy {
width: 100vw;
height: 100vh;
border-radius: 0;
}
}
/* Screen */
.screen {
background-color: #306230; /* Game Boy green screen */
border: 4px solid #0f380f;
width: 90%;
height: 55%;
margin-top: 20px;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
box-shadow: inset 0 4px 8px rgba(0, 0, 0, 0.5);
overflow: hidden;
}
.game {
text-align: center;
width: 90%;
}
/* Titles */
h1 {
font-size: 2rem; /* Increased font size */
margin-bottom: 10px;
text-transform: uppercase;
}
/* Guess Display */
.guess-display {
background-color: #9bbc0f;
color: #0f380f;
border: 2px solid #0f380f;
font-size: 2rem; /* Increased font size */
width: 80px; /* Increased width */
text-align: center;
margin: 10px auto;
padding: 10px; /* Increased padding */
border-radius: 4px;
}
/* Messages */
.message,
.score,
.highScore {
font-size: 1.4rem; /* Increased font size */
margin: 5px 0;
}
.description,
.description p {
font-size: 1.2rem;
margin: 0 auto;
padding: 0 auto;
}
/* Controls Section */
.controls {
margin-top: 20px;
display: flex;
justify-content: space-between;
width: 80%;
align-items: center;
}
/* D-Pad */
.dpad {
position: relative;
width: 120px; /* Increased size */
height: 120px; /* Increased size */
}
/* Base Styling for D-Pad Buttons */
.dpad-btn {
background-color: #0f380f;
color: #9bbc0f;
border: none;
border-radius: 5px;
position: absolute;
width: 42px;
height: 42px;
font-size: 1.5rem; /* Increased size */
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
z-index: 1;
}
.dpad-btn.up {
top: 0;
left: 50%;
transform: translateX(-50%);
}
.dpad-btn.down {
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
.dpad-btn.left {
top: 50%;
left: 0;
transform: translateY(-50%);
}
.dpad-btn.right {
top: 50%;
right: 0;
transform: translateY(-50%);
}
/* D-Pad Center to Connect Buttons */
.dpad-center {
background-color: #0f380f;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 40px;
height: 40px;
border: 2px solid #9cbc0f00;
z-index: 0;
border-radius: 5px;
}
/* A and B Buttons */
.action-buttons {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 140px; /* Increased height */
}
.btn {
background-color: #0f380f;
color: #9bbc0f;
border: 2px solid #9bbc0f;
border-radius: 50%;
width: 60px;
height: 60px;
font-size: 1.8rem; /* Increased font size */
cursor: pointer;
transition: transform 0.1s, background-color 0.2s;
}
.btn:hover {
background-color: #9bbc0f;
color: #0f380f;
}
.btn:active {
transform: scale(0.9);
}

View file

@ -1,148 +0,0 @@
"use strict";
const left = document.querySelector("#left");
const right = document.querySelector("#right");
const gameboy = document.querySelector(".gameboy");
const html = document.documentElement;
const body = document.body;
const screen = document.querySelector(".screen");
const dpadButtons = document.querySelectorAll(".dpad-btn");
const dpadCenter = document.querySelector(".dpad-center"); // Darker variant
const actionButtons = document.querySelectorAll(".btn");
const colors = [
{
gameboyColor: "#B39DDB",
htmlColor: "#D1C4E9",
screenColor: "#E1BEE7",
buttonColor: "#673AB7",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#5E35B1",
},
{
gameboyColor: "#FFC107",
htmlColor: "#FFF9C4",
screenColor: "#FFEB3B",
buttonColor: "#FF9800",
buttonTextColor: "#000000",
dpadCenterColor: "#EF6C00",
},
{
gameboyColor: "#8BC34A",
htmlColor: "#C5E1A5",
screenColor: "#A5D6A7",
buttonColor: "#FF5722",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#E64A19",
},
{
gameboyColor: "#F44336",
htmlColor: "#FFCDD2",
screenColor: "#EF9A9A",
buttonColor: "#E91E63",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#C2185B",
},
{
gameboyColor: "#03A9F4",
htmlColor: "#BBDEFB",
screenColor: "#90CAF9",
buttonColor: "#FFEB3B",
buttonTextColor: "#000000",
dpadCenterColor: "#0277BD",
},
{
gameboyColor: "#FF7043",
htmlColor: "#FFCCBC",
screenColor: "#FFAB91",
buttonColor: "#FF5722",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#D84315",
},
{
gameboyColor: "#9C27B0",
htmlColor: "#E1BEE7",
screenColor: "#D1C4E9",
buttonColor: "#7B1FA2",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#6A1B9A",
},
{
gameboyColor: "#FFD700",
htmlColor: "#FFF9C4",
screenColor: "#FFF59D",
buttonColor: "#FF9800",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#F57F17",
},
{
gameboyColor: "#009688",
htmlColor: "#B2DFDB",
screenColor: "#80CBC4",
buttonColor: "#4CAF50",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#00796B",
},
{
gameboyColor: "#795548",
htmlColor: "#D7CCC8",
screenColor: "#A1887F",
buttonColor: "#9E9E9E",
buttonTextColor: "#000000",
dpadCenterColor: "#5D4037",
},
{
gameboyColor: "#FF5733",
htmlColor: "#FFCCCB",
screenColor: "#FFABAB",
buttonColor: "#C70039",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#B71C1C",
},
{
gameboyColor: "#00BCD4",
htmlColor: "#B2EBF2",
screenColor: "#80DEEA",
buttonColor: "#00ACC1",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#00838F",
},
];
let currentColorIndex = localStorage.getItem("gameboyColorIndex")
? parseInt(localStorage.getItem("gameboyColorIndex"))
: 0;
function updateGameBoyColor() {
gameboy.style.backgroundColor = colors[currentColorIndex].gameboyColor;
html.style.backgroundColor = colors[currentColorIndex].htmlColor;
body.style.backgroundColor = colors[currentColorIndex].htmlColor;
screen.style.backgroundColor = colors[currentColorIndex].screenColor;
dpadButtons.forEach((button) => {
button.style.backgroundColor = colors[currentColorIndex].buttonColor;
button.style.color = colors[currentColorIndex].buttonTextColor;
});
// Using darker dpad center color
dpadCenter.style.backgroundColor = colors[currentColorIndex].dpadCenterColor;
dpadCenter.style.color = colors[currentColorIndex].buttonTextColor;
actionButtons.forEach((button) => {
button.style.backgroundColor = colors[currentColorIndex].buttonColor;
button.style.color = colors[currentColorIndex].buttonTextColor;
});
}
left.addEventListener("click", () => {
currentColorIndex = (currentColorIndex - 1 + colors.length) % colors.length;
localStorage.setItem("gameboyColorIndex", currentColorIndex);
updateGameBoyColor();
});
right.addEventListener("click", () => {
currentColorIndex = (currentColorIndex + 1) % colors.length;
localStorage.setItem("gameboyColorIndex", currentColorIndex);
updateGameBoyColor();
});
updateGameBoyColor();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 949 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 573 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

View file

@ -1,118 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Secret Game Collection</title>
<link rel="stylesheet" href="styles.css" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="../favicon_io/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="../favicon_io/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="../favicon_io/favicon-16x16.png"
/>
<link rel="manifest" href="../favicon_io/site.webmanifest" />
</head>
<body>
<header>
<h1>Secret Game Collection</h1>
</header>
<main>
<div class="grid-container">
<a
href="asteroidDestroyer/explenation.html"
target="_blank"
class="item"
>
<img src="images/asteroid.png" alt="Image can't be displayed" />
<h2>Secret Asteroid Shooter</h2>
<div class="description">
<p>
In this game, you control a spaceship that shoots at asteroids to
avoid destruction and collect items for power-ups.
</p>
<p>
Your goal is to survive as long as possible while scoring points!
</p>
</div>
</a>
<a href="#" target="_blank" class="item">
<img src="images/default.jpeg" alt="Image can't be displayed" />
<h2>Secret Blackjack</h2>
<div class="description">
<p>
Try to beat the dealer by getting a hand value as close to 21 as
possible without going over.
</p>
</div>
</a>
<a href="#" target="_blank" class="item">
<img src="images/default.jpeg" alt="Image can't be displayed" />
<h2>Snake</h2>
<div class="description">
<p>
Guide the snake to eat food and grow longer while avoiding
collisions with the walls and itself.
</p>
</div>
</a>
<a href="#" target="_blank" class="item">
<img src="images/default.jpeg" alt="Image can't be displayed" />
<h2>Solitaire</h2>
<div class="description">
<p>
A classic card game where the objective is to move all cards to
foundation piles in ascending order.
</p>
</div>
</a>
<a href="mineSweeper/index.html" target="_blank" class="item">
<img src="images/minesweeper.png" alt="Image can't be displayed" />
<h2>Minesweeper</h2>
<div class="description">
<p>
Uncover squares on a grid while avoiding hidden mines, using
numbers to deduce safe spots.
</p>
</div>
</a>
<a href="guessMyNumber/index.html" target="_blank" class="item">
<img src="images/number.jpeg" alt="Image can't be displayed" />
<h2>Guess My Number</h2>
<div class="description">
<p>
A simple game where you try to guess a randomly chosen number
within a certain range.
</p>
</div>
</a>
<a href="#" target="_blank" class="item">
<img src="images/default.jpeg" alt="Image can't be displayed" />
<h2>Endless Runner</h2>
<div class="description">
<p>
Run through an endless landscape, avoiding obstacles and
collecting items to score points.
</p>
</div>
</a>
</div>
</main>
<footer>
<p>&copy; 2025 Game Collection</p>
</footer>
</body>
</html>

View file

@ -1,60 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Minesweeper</title>
<link rel="stylesheet" href="styles.css" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="../../favicon_io/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="../../favicon_io/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="../../favicon_io/favicon-16x16.png"
/>
<link rel="manifest" href="../../favicon_io/site.webmanifest" />
</head>
<body>
<div id="settings">
<h1>Minesweeper</h1>
<label for="gridSize">Grid Size:</label>
<input
type="number"
id="gridSize"
min="6"
max="25"
value="9"
aria-label="Grid Size"
/>
<label for="bombs">Number of Bombs:</label>
<input
type="number"
id="bombs"
min="1"
max="300"
value="9"
aria-label="Number of Bombs"
/>
<button id="startGame">Start Game</button>
</div>
<div class="container">
<canvas id="game"></canvas>
</div>
<script src="script.js"></script>
</body>
</html>

View file

@ -1,192 +0,0 @@
document.getElementById("startGame").addEventListener("click", function () {
const gridSize = parseInt(document.getElementById("gridSize").value);
const bombs = parseInt(document.getElementById("bombs").value);
document.getElementById("settings").style.display = "none";
document.getElementById("game").style.display = "block";
renderGame(gridSize, bombs);
});
const canvas = document.getElementById("game");
const ctx = canvas.getContext("2d");
class Minesweeper {
constructor(width, height, bombs) {
this.size = 25;
this.field = new Array(width);
this.bombs = new Array(width);
for (let x = 0; x < this.field.length; x++) {
this.field[x] = new Array(height);
this.bombs[x] = new Array(height);
for (let y = 0; y < this.field[x].length; y++) {
this.field[x][y] = 1;
this.bombs[x][y] = false;
}
}
this.bombAmount =
bombs > (width * height) / 2 ? (width * height) / 2 : bombs;
this.width = width;
this.height = height;
this.firstClick = false;
this.drawField();
}
generateBombs() {
for (let i = 0; i < this.bombAmount; i++) {
let x = Math.floor(Math.random() * this.width);
let y = Math.floor(Math.random() * this.height);
this.bombs[x][y] || this.field[x][y] == 0
? i--
: (this.bombs[x][y] = true);
}
this.firstClick = true;
}
getNearbyBombs(x, y) {
let counter = 0;
for (let newX = x - 1; newX <= x + 1; newX++) {
for (let newY = y - 1; newY <= y + 1; newY++) {
if (
newX < this.field.length &&
newX >= 0 &&
newY < this.field[0].length &&
newY >= 0
) {
this.bombs[newX][newY] ? counter++ : {};
}
}
}
return counter;
}
checkWin() {
for (let x = 0; x < this.field.length; x++) {
for (let y = 0; y < this.field[x].length; y++) {
if (this.field[x][y] != 0 && !this.bombs[x][y]) {
return;
} else if (this.field[x][y] == 0 && this.bombs[x][y]) {
alert(`[ERROR]: Square (${x}|${y}) should not be a bomb!`);
this.bombs[x][y] = false;
}
}
}
this.drawField();
alert("You won!");
window.location.reload();
}
markSquare(x, y) {
if (x < this.field.length && y < this.field[0].length) {
switch (this.field[x][y]) {
case 1:
this.field[x][y]++;
break;
case 2:
this.field[x][y]++;
break;
case 3:
this.field[x][y] = 1;
break;
default:
break;
}
this.drawField();
}
}
uncoverSquare(x, y) {
if (x < this.field.length && x >= 0 && y < this.field[0].length && y >= 0) {
if (this.bombs[x][y] && this.field[x][y] == 1) {
alert("You lost!");
window.location.reload();
} else if (this.field[x][y] == 1) {
this.field[x][y] = 0;
!this.firstClick ? this.generateBombs() : {};
if (this.getNearbyBombs(x, y) == 0) {
for (let newX = x - 1; newX <= x + 1; newX++) {
for (let newY = y - 1; newY <= y + 1; newY++) {
if (
newX < this.field.length &&
newX >= 0 &&
newY < this.field[0].length &&
newY >= 0
) {
this.field[newX][newY] == 1
? this.uncoverSquare(newX, newY)
: {};
}
}
}
}
}
this.checkWin();
this.drawField();
}
}
drawSquare(x, y, type) {
ctx.lineWidth = 3;
let uncovered = (x + y) % 2 === 0 ? "#D3D3D3" : "#A9A9A9";
let covered = (x + y) % 2 === 0 ? "#4CAF50" : "#81C784";
ctx.fillStyle = type != 0 ? covered : uncovered;
ctx.fillRect(x * this.size, y * this.size, this.size, this.size);
ctx.strokeStyle = "#000";
ctx.strokeRect(x * this.size, y * this.size, this.size, this.size);
if (type != 1) {
const fontSize = this.size / 2;
const number = this.getNearbyBombs(x, y);
let finalPrint;
ctx.font = `${fontSize}px sans-serif`;
ctx.fillStyle = "#000";
type == 0 ? (finalPrint = number ? number : " ") : {};
type == 2 ? (finalPrint = "🚩") : {};
type == 3 ? (finalPrint = "❓") : {};
ctx.fillText(
finalPrint,
x * this.size + fontSize / (type == 0 ? 1.5 : 1.8),
y * this.size + fontSize * 1.3
);
}
}
drawField() {
if (window.innerWidth > window.innerHeight) {
this.size = window.innerHeight / (this.field[0].length + 4);
} else {
this.size = window.innerWidth / (this.field.length + 4);
}
canvas.width = this.size * this.field.length;
canvas.height = this.size * this.field[0].length;
const offsetX = (canvas.width - this.field.length * this.size) / 2;
const offsetY = (canvas.height - this.field[0].length * this.size) / 2;
for (let x = 0; x < this.field.length; x++) {
for (let y = 0; y < this.field[x].length; y++) {
this.drawSquare(x, y, this.field[x][y], offsetX, offsetY);
}
}
}
}
const renderGame = (gridSize, bombs) => {
let field = new Minesweeper(gridSize, gridSize, bombs);
window.addEventListener("resize", () => field.drawField());
canvas.addEventListener("click", (event) => {
const rect = canvas.getBoundingClientRect();
const x = Math.floor((event.clientX - rect.left) / field.size);
const y = Math.floor((event.clientY - rect.top) / field.size);
field.uncoverSquare(x, y);
});
canvas.addEventListener("contextmenu", (event) => {
event.preventDefault();
const rect = canvas.getBoundingClientRect();
const x = Math.floor((event.clientX - rect.left) / field.size);
const y = Math.floor((event.clientY - rect.top) / field.size);
field.markSquare(x, y);
});
};

View file

@ -1,104 +0,0 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body,
html {
height: 100%;
margin: 0;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background-color: #121212;
color: #e0e0e0;
}
#settings {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
margin: auto;
background-color: #1e1e1e;
padding: 40px;
border-radius: 12px;
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.5);
width: 100%;
max-width: 600px;
}
h1 {
font-size: 2.5em;
margin-bottom: 20px;
color: #007bff;
}
label {
margin-bottom: 12px;
font-size: 20px;
color: #d1d1d1;
}
input[type="number"],
input[type="range"],
span {
padding: 12px;
margin-bottom: 20px;
width: 100%;
max-width: 400px;
text-align: center;
border: 1px solid #444;
border-radius: 6px;
background-color: #333;
color: #e0e0e0;
font-size: 18px;
transition: border-color 0.3s ease;
}
input[type="number"]:focus,
input[type="range"]:focus {
border-color: #007bff;
outline: none;
}
button {
padding: 12px 24px;
background-color: #007bff;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease;
font-size: 18px;
}
button:hover {
background-color: #0056b3;
transform: translateY(-2px);
}
button:active {
transform: translateY(0);
}
canvas {
display: none;
}
@media (max-width: 600px) {
#settings {
font-size: 16px;
}
input[type="number"],
input[type="range"],
button {
width: 90%;
max-width: none;
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,95 +0,0 @@
"use strict";
const cvs = document.getElementById("snake");
const ctx = cvs.getContext("2d");
const box = 20;
let snake = [{ x: 9 * box, y: 10 * box }];
let food = {
x: Math.floor(Math.random() * 19 + 1) * box,
y: Math.floor(Math.random() * 19 + 1) * box,
};
let score = 0;
let d;
let game;
document.addEventListener("keydown", direction);
function direction(event) {
let key = event.keyCode;
if ((key == 37 || key == 65) && d != "RIGHT") d = "LEFT";
else if ((key == 38 || key == 87) && d != "DOWN") d = "UP";
else if ((key == 39 || key == 68) && d != "LEFT") d = "RIGHT";
else if ((key == 40 || key == 83) && d != "UP") d = "DOWN";
}
function collision(head, array) {
return array.some((part) => head.x == part.x && head.y == part.y);
}
function draw() {
ctx.fillStyle = "#0f380f";
ctx.fillRect(0, 0, cvs.width, cvs.height);
ctx.fillStyle = "red";
ctx.fillRect(food.x, food.y, box, box);
for (let i = 0; i < snake.length; i++) {
ctx.fillStyle = i == 0 ? "lime" : "white";
ctx.fillRect(snake[i].x, snake[i].y, box, box);
ctx.strokeStyle = "black";
ctx.strokeRect(snake[i].x, snake[i].y, box, box);
}
let snakeX = snake[0].x;
let snakeY = snake[0].y;
if (d == "LEFT") snakeX -= box;
if (d == "UP") snakeY -= box;
if (d == "RIGHT") snakeX += box;
if (d == "DOWN") snakeY += box;
if (snakeX == food.x && snakeY == food.y) {
score++;
food = {
x: Math.floor(Math.random() * 19 + 1) * box,
y: Math.floor(Math.random() * 19 + 1) * box,
};
} else {
snake.pop();
}
let newHead = { x: snakeX, y: snakeY };
if (
snakeX < 0 ||
snakeX >= cvs.width ||
snakeY < 0 ||
snakeY >= cvs.height ||
collision(newHead, snake)
) {
clearInterval(game);
document.getElementById("restartBtn").style.display = "block";
return;
}
snake.unshift(newHead);
ctx.fillStyle = "white";
ctx.font = "20px Arial";
ctx.fillText("Score: " + score, 10, 20);
}
function restartGame() {
snake = [{ x: 9 * box, y: 10 * box }];
food = {
x: Math.floor(Math.random() * 19 + 1) * box,
y: Math.floor(Math.random() * 19 + 1) * box,
};
score = 0;
d = "";
document.getElementById("restartBtn").style.display = "none";
game = setInterval(draw, 150);
}
document.getElementById("restartBtn").addEventListener("click", restartGame);
game = setInterval(draw, 150);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

View file

@ -1,67 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Snake - Game</title>
<link rel="stylesheet" href="styles.css" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="../../favicon_io/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="../../favicon_io/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="../../favicon_io/favicon-16x16.png"
/>
<link rel="manifest" href="../../favicon_io/site.webmanifest" />
</head>
<body>
<div class="gameboy">
<!-- Game Boy Screen -->
<div class="screen">
<article class="game">
<h1 class="title" id="title">Snake - Game</h1>
<div class="description" id="description">
<h2>Description</h2>
<p>Eat as many apples and grow as much as possible</p>
<p>◀ or A or arrow left = move left</p>
<p>▶ or D or arrow right = move right</p>
<p>▲ or W or arrow up = move up</p>
<p>▼ or S or arrow down = move down</p>
</div>
<canvas id="snake" width="400" height="400"></canvas>
</article>
</div>
<!-- Controls -->
<div class="controls">
<!-- D-Pad on the left -->
<div class="dpad">
<button class="dpad-btn up" id="up"></button>
<button class="dpad-btn left" id="left"></button>
<div class="dpad-center"></div>
<button class="dpad-btn right" id="right"></button>
<button class="dpad-btn down" id="down"></button>
</div>
<!-- A, B and start button on the right -->
<div class="action-buttons">
<button class="start-btn btn" id="start">Start</button>
<button class="btn" id="a">A</button>
<button class="btn" id="b">B</button>
</div>
</div>
</div>
<script src="game.js"></script>
<script src="styles.js"></script>
</body>
</html>

View file

@ -1,238 +0,0 @@
/* Base Reset */
body,
html {
margin: 0;
padding: 0;
font-family: monospace;
background-color: #3a2d56;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
/* GameBoy Layout */
.gameboy {
background-color: #5f4c82;
width: 441px;
height: 735px;
border-radius: 20px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.6);
display: flex;
flex-direction: column;
align-items: center;
padding: 10px;
position: relative;
}
@media (max-width: 768px) {
.gameboy {
width: 100vw;
height: 100vh;
border-radius: 0;
}
}
/* Screen */
.screen {
background-color: black;
border: 4px solid #0f380f;
width: 90%;
height: 55%;
margin-top: 20px;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
box-shadow: inset 0 4px 8px rgba(0, 0, 0, 0.5);
overflow: hidden;
}
.game {
text-align: center;
width: 90%;
}
/* Titles */
h1 {
font-size: 2rem;
margin-bottom: 10px;
text-transform: uppercase;
color: #9bbc0f;
}
.description,
.description p {
font-size: 1.2rem;
margin: 0 auto;
padding: 0 auto;
color: white;
}
/* Grid container */
#grid {
display: grid;
grid-template-columns: repeat(10, 1fr); /* Adjust to match gridSize */
grid-template-rows: repeat(10, 1fr); /* Adjust to match gridSize */
width: 400px; /* Adjust as needed */
height: 400px; /* Adjust as needed */
border: 2px solid #0f380f;
margin: 20px auto;
/* initially hide */
display: none;
}
/* Individual cells */
.cell {
width: 100%;
height: 100%;
}
.cell.light-green {
background-color: #9bbc0f;
}
.cell.dark-green {
background-color: #0f380f;
}
/* Snake styling */
.snake {
background-color: #e600ff; /* Snake color */
z-index: 1000;
}
/* Apple styling */
.apple {
background-color: red; /* Apple color */
z-index: 999;
}
/* Controls Section */
.controls {
margin-top: 20px;
display: flex;
justify-content: space-between;
width: 80%;
align-items: center;
}
/* D-Pad */
.dpad {
position: relative;
width: 120px;
height: 120px;
}
/* Base Styling for D-Pad Buttons */
.dpad-btn {
background-color: #0f380f;
color: #9bbc0f;
border: none;
border-radius: 5px;
position: absolute;
width: 42px;
height: 42px;
font-size: 1.5rem;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
z-index: 1;
}
.dpad-btn.up {
top: 0;
left: 50%;
transform: translateX(-50%);
}
.dpad-btn.down {
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
.dpad-btn.left {
top: 50%;
left: 0;
transform: translateY(-50%);
}
.dpad-btn.right {
top: 50%;
right: 0;
transform: translateY(-50%);
}
/* D-Pad Center to Connect Buttons */
.dpad-center {
background-color: #0f380f;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 40px;
height: 40px;
border: 2px solid transparent;
z-index: 0;
border-radius: 5px;
}
/* A and B Buttons */
.action-buttons {
display: flex;
flex-direction: column;
justify-content: space-between;
height: 200px;
}
.btn {
background-color: #0f380f;
color: #9bbc0f;
border: 2px solid #9bbc0f;
border-radius: 50%;
width: 60px;
height: 60px;
font-size: 1.8rem;
cursor: pointer;
transition: transform 0.1s, background-color 0.2s;
}
.btn:hover {
background-color: #9bbc0f;
color: #0f380f;
}
.btn:active {
transform: scale(0.9);
}
/* Start Button */
.start-btn {
background-color: #0f380f;
color: #9bbc0f;
border: 2px solid #9bbc0f;
border-radius: 5px;
width: 100px;
height: 40px;
font-size: 1.2rem;
cursor: pointer;
transition: transform 0.1s, background-color 0.2s;
margin-bottom: 20px;
}
.start-btn:hover {
background-color: #9bbc0f;
color: #0f380f;
}
.start-btn:active {
transform: scale(0.9);
}
/* Hidden Canvas for Debugging or Fallback */
canvas {
display: none;
z-index: 1000;
}

View file

@ -1,134 +0,0 @@
"use strict";
const aBtn = document.querySelector("#a");
const bBtn = document.querySelector("#b");
const gameboy = document.querySelector(".gameboy");
const html = document.documentElement;
const body = document.body;
const dpadButtons = document.querySelectorAll(".dpad-btn");
const dpadCenter = document.querySelector(".dpad-center"); // Darker variant
const actionButtons = document.querySelectorAll(".btn");
const colors = [
{
gameboyColor: "#B39DDB",
htmlColor: "#D1C4E9",
buttonColor: "#673AB7",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#5E35B1",
},
{
gameboyColor: "#FFC107",
htmlColor: "#FFF9C4",
buttonColor: "#FF9800",
buttonTextColor: "#000000",
dpadCenterColor: "#EF6C00",
},
{
gameboyColor: "#8BC34A",
htmlColor: "#C5E1A5",
buttonColor: "#FF5722",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#E64A19",
},
{
gameboyColor: "#F44336",
htmlColor: "#FFCDD2",
buttonColor: "#E91E63",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#C2185B",
},
{
gameboyColor: "#03A9F4",
htmlColor: "#BBDEFB",
buttonColor: "#FFEB3B",
buttonTextColor: "#000000",
dpadCenterColor: "#0277BD",
},
{
gameboyColor: "#FF7043",
htmlColor: "#FFCCBC",
buttonColor: "#FF5722",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#D84315",
},
{
gameboyColor: "#9C27B0",
htmlColor: "#E1BEE7",
buttonColor: "#7B1FA2",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#6A1B9A",
},
{
gameboyColor: "#FFD700",
htmlColor: "#FFF9C4",
buttonColor: "#FF9800",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#F57F17",
},
{
gameboyColor: "#009688",
htmlColor: "#B2DFDB",
buttonColor: "#4CAF50",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#00796B",
},
{
gameboyColor: "#795548",
htmlColor: "#D7CCC8",
buttonColor: "#9E9E9E",
buttonTextColor: "#000000",
dpadCenterColor: "#5D4037",
},
{
gameboyColor: "#FF5733",
htmlColor: "#FFCCCB",
buttonColor: "#C70039",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#B71C1C",
},
{
gameboyColor: "#00BCD4",
htmlColor: "#B2EBF2",
buttonColor: "#00ACC1",
buttonTextColor: "#FFFFFF",
dpadCenterColor: "#00838F",
},
];
let currentColorIndex = localStorage.getItem("gameboyColorIndex")
? parseInt(localStorage.getItem("gameboyColorIndex"))
: 0;
function updateGameBoyColor() {
gameboy.style.backgroundColor = colors[currentColorIndex].gameboyColor;
html.style.backgroundColor = colors[currentColorIndex].htmlColor;
body.style.backgroundColor = colors[currentColorIndex].htmlColor;
dpadButtons.forEach((button) => {
button.style.backgroundColor = colors[currentColorIndex].buttonColor;
button.style.color = colors[currentColorIndex].buttonTextColor;
});
// Using darker dpad center color
dpadCenter.style.backgroundColor = colors[currentColorIndex].dpadCenterColor;
dpadCenter.style.color = colors[currentColorIndex].buttonTextColor;
actionButtons.forEach((button) => {
button.style.backgroundColor = colors[currentColorIndex].buttonColor;
button.style.color = colors[currentColorIndex].buttonTextColor;
});
}
aBtn.addEventListener("click", () => {
currentColorIndex = (currentColorIndex - 1 + colors.length) % colors.length;
localStorage.setItem("gameboyColorIndex", currentColorIndex);
updateGameBoyColor();
});
bBtn.addEventListener("click", () => {
currentColorIndex = (currentColorIndex + 1) % colors.length;
localStorage.setItem("gameboyColorIndex", currentColorIndex);
updateGameBoyColor();
});
updateGameBoyColor();

View file

@ -1,197 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Snake Game - GameBoy Style</title>
<style>
/* Base Reset */
body,
html {
margin: 0;
padding: 0;
font-family: monospace;
background-color: #3a2d56;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
/* GameBoy Layout */
.gameboy {
background-color: #5f4c82;
width: 441px;
height: 735px;
border-radius: 20px;
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.6);
display: flex;
flex-direction: column;
align-items: center;
padding: 10px;
position: relative;
}
@media (max-width: 768px) {
.gameboy {
width: 100vw;
height: 100vh;
border-radius: 0;
}
}
/* Screen */
.screen {
background-color: black;
border: 4px solid #0f380f;
width: 90%;
height: 55%;
margin-top: 20px;
border-radius: 10px;
display: flex;
justify-content: center;
align-items: center;
box-shadow: inset 0 4px 8px rgba(0, 0, 0, 0.5);
overflow: hidden;
}
canvas {
border: 1px solid black;
}
/* Restart Button */
#restartBtn {
padding: 10px 20px;
font-size: 16px;
cursor: pointer;
margin-top: 20px;
background-color: #0f380f;
color: white;
border: none;
border-radius: 5px;
display: none;
}
#restartBtn:hover {
background-color: #9bbc0f;
}
/* Titles */
h1 {
font-size: 1.8rem;
margin-bottom: 10px;
text-transform: uppercase;
color: #9bbc0f;
}
</style>
</head>
<body>
<div class="gameboy">
<h1>Snake Game</h1>
<div class="screen">
<canvas id="snake" width="400" height="400"></canvas>
</div>
<button id="restartBtn">Restart</button>
</div>
<script>
"use strict";
const cvs = document.getElementById("snake");
const ctx = cvs.getContext("2d");
const box = 20;
let snake = [{ x: 9 * box, y: 10 * box }];
let food = {
x: Math.floor(Math.random() * 19 + 1) * box,
y: Math.floor(Math.random() * 19 + 1) * box,
};
let score = 0;
let d;
let game;
document.addEventListener("keydown", direction);
function direction(event) {
let key = event.keyCode;
if ((key == 37 || key == 65) && d != "RIGHT") d = "LEFT";
else if ((key == 38 || key == 87) && d != "DOWN") d = "UP";
else if ((key == 39 || key == 68) && d != "LEFT") d = "RIGHT";
else if ((key == 40 || key == 83) && d != "UP") d = "DOWN";
}
function collision(head, array) {
return array.some((part) => head.x == part.x && head.y == part.y);
}
function draw() {
ctx.fillStyle = "#0f380f";
ctx.fillRect(0, 0, cvs.width, cvs.height);
ctx.fillStyle = "red";
ctx.fillRect(food.x, food.y, box, box);
for (let i = 0; i < snake.length; i++) {
ctx.fillStyle = i == 0 ? "lime" : "white";
ctx.fillRect(snake[i].x, snake[i].y, box, box);
ctx.strokeStyle = "black";
ctx.strokeRect(snake[i].x, snake[i].y, box, box);
}
let snakeX = snake[0].x;
let snakeY = snake[0].y;
if (d == "LEFT") snakeX -= box;
if (d == "UP") snakeY -= box;
if (d == "RIGHT") snakeX += box;
if (d == "DOWN") snakeY += box;
if (snakeX == food.x && snakeY == food.y) {
score++;
food = {
x: Math.floor(Math.random() * 19 + 1) * box,
y: Math.floor(Math.random() * 19 + 1) * box,
};
} else {
snake.pop();
}
let newHead = { x: snakeX, y: snakeY };
if (
snakeX < 0 ||
snakeX >= cvs.width ||
snakeY < 0 ||
snakeY >= cvs.height ||
collision(newHead, snake)
) {
clearInterval(game);
document.getElementById("restartBtn").style.display = "block";
return;
}
snake.unshift(newHead);
ctx.fillStyle = "white";
ctx.font = "20px Arial";
ctx.fillText("Score: " + score, 10, 20);
}
function restartGame() {
snake = [{ x: 9 * box, y: 10 * box }];
food = {
x: Math.floor(Math.random() * 19 + 1) * box,
y: Math.floor(Math.random() * 19 + 1) * box,
};
score = 0;
d = "";
document.getElementById("restartBtn").style.display = "none";
game = setInterval(draw, 150);
}
document
.getElementById("restartBtn")
.addEventListener("click", restartGame);
game = setInterval(draw, 150);
</script>
</body>
</html>

View file

@ -1,145 +0,0 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: "Courier New", Courier, monospace;
background-color: #0d0d0d;
color: #b0b0b0;
margin: 0;
line-height: 1.6;
background-image: url("images/background.jpg");
background-size: cover; /* Adjust size for tape appearance */
}
header {
background-color: #222; /* Fully opaque background */
color: #b0b0b0;
text-align: center;
padding: 1em 0;
font-size: 2rem;
text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.7);
animation: neonFlicker 1.5s infinite;
}
/* Create the flickering neon light effect */
@keyframes neonFlicker {
0% {
text-shadow: 0 0 5px #ffcc00, 0 0 10px #ffcc00, 0 0 15px #ffcc00,
0 0 20px #ffcc00, 0 0 30px #ffcc00, 0 0 40px #ffcc00, 0 0 50px #ffcc00;
}
20% {
text-shadow: 0 0 3px #ffcc00, 0 0 7px #ffcc00, 0 0 10px #ffcc00,
0 0 15px #ffcc00, 0 0 20px #ffcc00;
}
40% {
text-shadow: 0 0 5px #ffcc00, 0 0 15px #ffcc00, 0 0 25px #ffcc00;
}
60% {
text-shadow: 0 0 5px #ffcc00, 0 0 10px #ffcc00, 0 0 15px #ffcc00,
0 0 20px #ffcc00, 0 0 30px #ffcc00;
}
80% {
text-shadow: 0 0 3px #ffcc00, 0 0 7px #ffcc00, 0 0 10px #ffcc00;
}
100% {
text-shadow: 0 0 5px #ffcc00, 0 0 10px #ffcc00, 0 0 15px #ffcc00,
0 0 20px #ffcc00, 0 0 30px #ffcc00, 0 0 40px #ffcc00;
}
}
footer {
background-color: #111;
color: #b0b0b0;
text-align: center;
padding: 1em 0;
margin-top: 20px;
}
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
padding: 20px;
}
.item {
position: relative;
background-color: #1a1a1a;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.8);
transition: transform 0.3s ease, box-shadow 0.3s ease, filter 0.3s ease;
width: 100%;
height: 400px;
display: flex;
flex-direction: column;
}
.item img {
width: 100%;
height: 100%;
object-fit: cover;
filter: brightness(0.6);
}
.item .description {
padding: 30px;
font-size: 1rem;
color: #ccc;
background-color: rgba(0, 0, 0, 0.8);
border-radius: 0 0 10px 10px;
flex-grow: 1;
}
p {
text-decoration: none;
}
.item:hover {
transform: scale(1.05);
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.9);
filter: brightness(1.1);
}
.item:hover img {
transform: scale(1.1);
filter: brightness(1.1);
}
.item h2 {
position: absolute;
top: 10%;
left: 50%;
transform: translateX(-50%);
color: #ffffff;
font-size: 1.8rem;
background-color: rgba(0, 0, 0, 0.9);
padding: 5px 15px;
border-radius: 5px;
text-align: center;
opacity: 0;
transition: opacity 0.3s ease, transform 0.3s ease;
}
.item:hover h2 {
opacity: 1;
transform: translateX(-50%) translateY(-10px);
}
@media (max-width: 800px) {
header {
font-size: 1.5rem;
}
.item {
height: auto;
width: auto;
}
.grid-container {
grid-template-columns: repeat(1, 1fr);
}
}

View file

Before

Width:  |  Height:  |  Size: 173 KiB

After

Width:  |  Height:  |  Size: 173 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 385 KiB

After

Width:  |  Height:  |  Size: 385 KiB

Before After
Before After

22
src/scripts/form.js Normal file
View file

@ -0,0 +1,22 @@
// Form submission
function setupForm() {
const form = document.getElementById("contact-form");
if (form) {
form.addEventListener("submit", function (e) {
e.preventDefault();
// Simple form validation
const name = document.getElementById("name").value;
const email = document.getElementById("email").value;
const message = document.getElementById("message").value;
if (name && email && message) {
// In a real implementation, you would send the form data to a server
alert("Thank you for your message! We will get back to you soon.");
form.reset();
} else {
alert("Please fill in all required fields.");
}
});
}
}

27
src/scripts/main.js Normal file
View file

@ -0,0 +1,27 @@
// Initialize everything when DOM is loaded
document.addEventListener("DOMContentLoaded", function () {
// Initialize components
if (typeof createStars === "function") createStars();
if (typeof updateNavigation === "function") updateNavigation();
if (typeof setupForm === "function") setupForm();
if (typeof setupMobileNavigation === "function") setupMobileNavigation();
// Set up event listeners
window.addEventListener("scroll", updateNavigation);
// Smooth scrolling for navigation links
document.querySelectorAll('a[href^="#"]').forEach((anchor) => {
anchor.addEventListener("click", function (e) {
e.preventDefault();
const targetId = this.getAttribute("href");
if (targetId === "#") return;
const targetElement = document.querySelector(targetId);
if (targetElement) {
targetElement.scrollIntoView({
behavior: "smooth",
});
}
});
});
});

33
src/scripts/navigation.js Normal file
View file

@ -0,0 +1,33 @@
// Navigation scroll effect
function updateNavigation() {
const navigation = document.getElementById("navigation");
if (window.scrollY > 50) {
navigation.classList.add("scrolled");
} else {
navigation.classList.remove("scrolled");
}
}
// Mobile navigation functionality
function setupMobileNavigation() {
const burgerMenu = document.getElementById("burger-menu");
const mainNav = document.getElementById("main-nav");
if (burgerMenu && mainNav) {
burgerMenu.addEventListener("click", function () {
mainNav.classList.toggle("active");
burgerMenu.classList.toggle("active");
document.body.classList.toggle("nav-open");
});
// Close menu when clicking on a link
const navLinks = mainNav.querySelectorAll("a");
navLinks.forEach((link) => {
link.addEventListener("click", function () {
mainNav.classList.remove("active");
burgerMenu.classList.remove("active");
document.body.classList.remove("nav-open");
});
});
}
}

56
src/scripts/overview.js Normal file
View file

@ -0,0 +1,56 @@
// Counter animation for stats
document.addEventListener("DOMContentLoaded", function() {
const counters = document.querySelectorAll('.stat-number');
let hasCounted = false;
function animateCounters() {
if (hasCounted) return;
counters.forEach(counter => {
const target = parseInt(counter.getAttribute('data-count'));
const duration = 2000; // 2 seconds
const frameDuration = 1000 / 60; // 60 frames per second
const totalFrames = Math.round(duration / frameDuration);
let frame = 0;
const counterInterval = setInterval(() => {
frame++;
const progress = frame / totalFrames;
const currentCount = Math.round(target * progress);
counter.textContent = currentCount;
if (frame === totalFrames) {
clearInterval(counterInterval);
}
}, frameDuration);
counter.classList.add('animated');
});
hasCounted = true;
}
// Check if element is in viewport
function isInViewport(element) {
const rect = element.getBoundingClientRect();
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
// Check on scroll and on load
function checkCounters() {
const statsContainer = document.querySelector('.stats-container');
if (statsContainer && isInViewport(statsContainer)) {
animateCounters();
window.removeEventListener('scroll', checkCounters);
}
}
window.addEventListener('scroll', checkCounters);
checkCounters(); // Check on page load
});

View file

@ -0,0 +1,228 @@
class PortfolioCard extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: "open" });
const icon = this.getAttribute("icon") || "fas fa-code";
const title = this.getAttribute("title") || "Project Title";
const desc = this.getAttribute("desc") || "Project description goes here.";
const tags = (this.getAttribute("tags") || "").split(",");
const link = this.getAttribute("link") || "#";
const collaboration = this.getAttribute("collaboration") || "";
shadow.innerHTML = `
<!-- Font Awesome inside Shadow DOM -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Use global styles.css from index.html -->
<link rel="stylesheet" href="src/styles/styles.css">
<style>
/* Collaboration badge styling */
.collaboration-badge {
display: inline-flex;
align-items: center;
gap: 0.4rem;
background: linear-gradient(135deg, #3b82f6, #2563eb);
color: white;
padding: 0.3rem 0.8rem;
border-radius: 20px;
font-size: 0.75rem;
margin-top: 0.5rem;
margin-bottom: 1rem;
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
box-shadow: 0 0 0 0 rgba(59, 130, 246, 0.4);
}
70% {
box-shadow: 0 0 0 10px rgba(59, 130, 246, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(59, 130, 246, 0);
}
}
/* Enhanced card animations */
.portfolio-item {
opacity: 0;
transform: translateY(20px);
animation: fadeInUp 0.6s ease forwards;
display: flex;
flex-direction: column;
height: 100%;
}
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Portfolio title with icon */
.portfolio-title {
display: flex;
align-items: center;
gap: 0.5rem;
}
.portfolio-content {
display: flex;
flex-direction: column;
flex: 1;
padding: 1.5rem;
}
.portfolio-tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
/* Full-width Enhanced Button Styles */
.portfolio-btn-container {
margin-top: auto;
padding: 0 1.5rem 1.5rem;
}
.portfolio-btn {
width: 100%;
position: relative;
overflow: hidden;
z-index: 1;
padding: 1rem 1.8rem;
border-radius: 8px;
font-weight: 600;
letter-spacing: 0.5px;
text-transform: uppercase;
font-size: 0.9rem;
transition: all 0.4s cubic-bezier(0.165, 0.84, 0.44, 1);
border: 2px solid transparent;
background: linear-gradient(135deg, var(--purple), var(--purple-dark));
color: white;
box-shadow: 0 4px 15px var(--shadow-purple);
display: flex;
justify-content: center;
align-items: center;
gap: 0.8rem;
text-decoration: none;
text-align: center;
}
.portfolio-btn::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg, var(--purple-dark), var(--purple-muted));
z-index: -1;
transition: transform 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
transform: scaleX(0);
transform-origin: right;
}
.portfolio-btn:hover::before {
transform: scaleX(1);
transform-origin: left;
}
.portfolio-btn:hover {
transform: translateY(-3px);
box-shadow: 0 8px 25px rgba(168, 85, 247, 0.4);
border-color: var(--purple-light);
}
.portfolio-btn:active {
transform: translateY(0);
box-shadow: 0 4px 15px var(--shadow-purple);
}
.portfolio-btn i {
font-size: 1rem;
transition: transform 0.3s ease;
}
.portfolio-btn:hover i {
transform: translateX(4px);
}
.portfolio-btn::after {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(
to bottom right,
rgba(255, 255, 255, 0.2),
rgba(255, 255, 255, 0.1) 20%,
rgba(255, 255, 255, 0) 50%,
rgba(255, 255, 255, 0) 100%
);
transform: rotate(30deg) translateY(-150%);
transition: transform 0.6s cubic-bezier(0.165, 0.84, 0.44, 1);
}
.portfolio-btn:hover::after {
transform: rotate(30deg) translateY(150%);
}
.portfolio-btn:focus {
outline: 2px solid var(--purple-light);
outline-offset: 2px;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.portfolio-btn {
padding: 0.9rem 1.5rem;
font-size: 0.85rem;
}
}
</style>
<div class="portfolio-item">
<div class="portfolio-img">
<i class="${icon}"></i>
</div>
<div class="portfolio-content">
<h3 class="portfolio-title">
<i class="${icon}"></i> ${title}
</h3>
<p class="portfolio-desc">${desc}</p>
${
collaboration
? `
<div class="collaboration-badge">
<i class="fas fa-users"></i> ${collaboration}
</div>
`
: ""
}
<div class="portfolio-tags">
${tags
.map((tag) => `<span class="tag">${tag.trim()}</span>`)
.join("")}
</div>
</div>
<div class="portfolio-btn-container">
<a href="${link}" target="_blank" class="portfolio-btn">
<i class="fas fa-arrow-right"></i> Explore Project
</a>
</div>
</div>
`;
}
}
customElements.define("portfolio-card", PortfolioCard);

View file

@ -0,0 +1,95 @@
// Portfolio filtering functionality
document.addEventListener("DOMContentLoaded", function () {
// Get all portfolio items
const portfolioItems = document.querySelectorAll("portfolio-card");
const filterButtons = document.querySelectorAll(".filter-btn");
const searchInput = document.getElementById("project-search");
// Create a container for no results message
const noResults = document.createElement("div");
noResults.className = "no-results";
noResults.innerHTML = `
<i class="fas fa-search"></i>
<h3>No projects found</h3>
<p>Try adjusting your search or filter criteria</p>
`;
// Function to filter portfolio items
function filterPortfolio() {
const activeFilter =
document.querySelector(".filter-btn.active").dataset.filter;
const searchTerm = searchInput.value.toLowerCase();
let visibleItems = 0;
portfolioItems.forEach((item) => {
const tags = item.getAttribute("tags").toLowerCase();
const title = item.getAttribute("title").toLowerCase();
const desc = item.getAttribute("desc").toLowerCase();
// Check if item matches the active filter
const matchesFilter =
activeFilter === "all" ||
tags.includes(activeFilter) ||
title.includes(activeFilter) ||
desc.includes(activeFilter);
// Check if item matches the search term
const matchesSearch =
searchTerm === "" ||
title.includes(searchTerm) ||
desc.includes(searchTerm) ||
tags.includes(searchTerm);
// Show or hide the item based on filters
if (matchesFilter && matchesSearch) {
item.style.display = "block";
visibleItems++;
// Add animation for appearing items
item.style.animation = "fadeInUp 0.5s ease forwards";
} else {
item.style.display = "none";
}
});
// Show no results message if needed
const portfolioGrid = document.querySelector(".portfolio-grid");
const existingNoResults = portfolioGrid.querySelector(".no-results");
if (visibleItems === 0) {
if (!existingNoResults) {
portfolioGrid.appendChild(noResults);
}
} else if (existingNoResults) {
portfolioGrid.removeChild(existingNoResults);
}
}
// Add click event listeners to filter buttons
filterButtons.forEach((button) => {
button.addEventListener("click", function () {
// Remove active class from all buttons
filterButtons.forEach((btn) => btn.classList.remove("active"));
// Add active class to clicked button
this.classList.add("active");
// Filter portfolio items
filterPortfolio();
});
});
// Add input event listener to search field
searchInput.addEventListener("input", filterPortfolio);
// Add keyboard shortcut for search (Ctrl/Cmd + F)
document.addEventListener("keydown", function (e) {
if ((e.ctrlKey || e.metaKey) && e.key === "f") {
e.preventDefault();
searchInput.focus();
}
});
// Initialize filter on page load
filterPortfolio();
});

22
src/scripts/stars.js Normal file
View file

@ -0,0 +1,22 @@
// Create stellar background
function createStars() {
const stars = document.getElementById("stars");
const count = 150;
stars.innerHTML = ""; // Clear any existing stars
for (let i = 0; i < count; i++) {
const star = document.createElement("div");
star.classList.add("star");
const size = Math.random() * 3;
star.style.width = `${size}px`;
star.style.height = `${size}px`;
star.style.left = `${Math.random() * 100}%`;
star.style.top = `${Math.random() * 100}%`;
star.style.animationDelay = `${Math.random() * 5}s`;
stars.appendChild(star);
}
}

998
src/styles/styles.css Normal file
View file

@ -0,0 +1,998 @@
/* Modern CSS Reset and Variables */
:root {
/* Color System */
--bg-primary: #0a0a0a;
--bg-secondary: #111111;
--bg-tertiary: #1a1a1a;
--bg-card: #161616;
--bg-card-hover: #1e1e1e;
--text-primary: #ffffff;
--text-secondary: #b3b3b3;
--text-muted: #737373;
--accent-primary: #00f5ff;
--accent-secondary: #7c3aed;
--accent-gradient: linear-gradient(135deg, #00f5ff, #7c3aed);
--border-subtle: #262626;
--border-accent: #333333;
/* Shadows */
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1);
--shadow-glow: 0 0 20px rgba(0, 245, 255, 0.1);
/* Border Radius */
--radius-sm: 8px;
--radius-md: 12px;
--radius-lg: 16px;
--radius-xl: 24px;
/* Spacing */
--spacing-xs: 0.5rem;
--spacing-sm: 1rem;
--spacing-md: 1.5rem;
--spacing-lg: 2rem;
--spacing-xl: 3rem;
--spacing-2xl: 4rem;
/* Typography */
--font-primary: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
--font-mono: "JetBrains Mono", "Fira Code", Consolas, monospace;
/* Z-Index Scale */
--z-navigation: 1000;
--z-modal: 1100;
--z-tooltip: 1200;
}
/* Reset */
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
scroll-behavior: smooth;
font-size: 16px;
}
body {
font-family: var(--font-primary);
background: var(--bg-primary);
color: var(--text-primary);
line-height: 1.6;
overflow-x: hidden;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Links */
a {
color: inherit;
text-decoration: none;
}
/* Lists */
ul,
ol {
list-style: none;
}
/* Images */
img {
max-width: 100%;
height: auto;
}
/* Focus States */
*:focus {
outline: 2px solid var(--accent-primary);
outline-offset: 2px;
}
/* Background Effects */
.animated-bg {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
background: radial-gradient(
circle at 20% 50%,
rgba(124, 58, 237, 0.08) 0%,
transparent 50%
),
radial-gradient(
circle at 80% 20%,
rgba(0, 245, 255, 0.06) 0%,
transparent 50%
),
radial-gradient(
circle at 40% 80%,
rgba(124, 58, 237, 0.04) 0%,
transparent 50%
);
}
.stars {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: -1;
}
.star {
position: absolute;
width: 1px;
height: 1px;
background: rgba(255, 255, 255, 0.8);
border-radius: 50%;
animation: twinkle 3s infinite ease-in-out;
}
@keyframes twinkle {
0%,
100% {
opacity: 0.3;
transform: scale(1);
}
50% {
opacity: 1;
transform: scale(1.2);
}
}
/* Navigation */
nav {
position: fixed;
top: 0;
width: 100%;
background: rgba(10, 10, 10, 0.8);
backdrop-filter: blur(20px);
border-bottom: 1px solid var(--border-subtle);
z-index: var(--z-navigation);
transition: all 0.3s ease;
}
nav.scrolled {
background: rgba(10, 10, 10, 0.95);
box-shadow: var(--shadow-lg);
}
.nav-container {
max-width: 1400px;
margin: 0 auto;
padding: 0 var(--spacing-lg);
display: flex;
align-items: center;
justify-content: space-between;
height: 80px;
}
.logo {
font-weight: 800;
font-size: 1.5rem;
background: var(--accent-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.nav-links {
display: flex;
gap: var(--spacing-lg);
}
.nav-links a {
color: var(--text-secondary);
font-weight: 500;
font-size: 0.9rem;
transition: all 0.3s ease;
position: relative;
padding: var(--spacing-xs) 0;
}
.nav-links a:hover {
color: var(--accent-primary);
}
.nav-links a::after {
content: "";
position: absolute;
bottom: -8px;
left: 0;
width: 0;
height: 2px;
background: var(--accent-primary);
transition: width 0.3s ease;
}
.nav-links a:hover::after {
width: 100%;
}
.mobile-menu-btn {
display: none;
background: none;
border: none;
color: var(--text-primary);
font-size: 1.5rem;
cursor: pointer;
padding: var(--spacing-xs);
border-radius: var(--radius-sm);
transition: background 0.3s ease;
}
.mobile-menu-btn:hover {
background: var(--bg-card);
}
/* Container */
.container {
max-width: 1400px;
margin: 0 auto;
padding: 0 var(--spacing-lg);
}
/* Hero Section */
.hero {
min-height: 100vh;
display: flex;
align-items: center;
padding-top: 80px;
}
.hero-content {
max-width: 800px;
margin: 0 auto;
text-align: center;
padding: var(--spacing-lg) 0;
}
.hero h1 {
font-size: clamp(2.5rem, 6vw, 4rem);
font-weight: 800;
margin-bottom: var(--spacing-md);
line-height: 1.1;
letter-spacing: -0.02em;
}
.hero h1 .highlight {
background: var(--accent-gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero p {
font-size: 1.25rem;
color: var(--text-secondary);
margin-bottom: var(--spacing-xl);
max-width: 600px;
margin-left: auto;
margin-right: auto;
line-height: 1.6;
}
.hero-buttons {
display: flex;
gap: var(--spacing-sm);
justify-content: center;
flex-wrap: wrap;
}
/* Buttons */
.btn {
display: inline-flex;
align-items: center;
gap: var(--spacing-xs);
padding: 0.875rem var(--spacing-lg);
border-radius: var(--radius-md);
font-weight: 600;
font-size: 0.9rem;
text-decoration: none;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: none;
cursor: pointer;
position: relative;
overflow: hidden;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.btn-primary {
background: var(--accent-gradient);
color: var(--bg-primary);
box-shadow: var(--shadow-glow);
}
.btn-primary:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 10px 25px rgba(0, 245, 255, 0.3);
}
.btn-secondary {
background: transparent;
color: var(--text-primary);
border: 2px solid var(--border-accent);
}
.btn-secondary:hover:not(:disabled) {
background: var(--bg-card);
border-color: var(--accent-primary);
transform: translateY(-2px);
}
/* Sections */
.section {
padding: 6rem 0;
}
.section-header {
text-align: center;
margin-bottom: var(--spacing-2xl);
}
.section-title {
font-size: clamp(2rem, 4vw, 3rem);
font-weight: 700;
margin-bottom: var(--spacing-sm);
letter-spacing: -0.02em;
}
.section-subtitle {
font-size: 1.125rem;
color: var(--text-secondary);
max-width: 600px;
margin: 0 auto;
line-height: 1.6;
}
/* Projects */
.project-category {
margin-bottom: var(--spacing-2xl);
}
.category-title {
font-size: 1.5rem;
font-weight: 600;
margin-bottom: var(--spacing-lg);
color: var(--text-primary);
}
.projects-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: var(--spacing-lg);
}
.project-card {
background: var(--bg-card);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-lg);
padding: var(--spacing-lg);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
position: relative;
overflow: hidden;
}
.project-card::before {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 3px;
background: var(--accent-gradient);
}
.project-card:hover {
transform: translateY(-8px);
background: var(--bg-card-hover);
box-shadow: var(--shadow-xl);
border-color: var(--border-accent);
}
.project-icon {
display: flex;
align-items: center;
justify-content: center;
width: 60px;
height: 60px;
background: var(--accent-gradient);
border-radius: var(--radius-md);
margin-bottom: var(--spacing-md);
font-size: 1.5rem;
color: var(--bg-primary);
}
.project-card h3 {
font-size: 1.5rem;
font-weight: 600;
margin-bottom: var(--spacing-sm);
color: var(--text-primary);
}
.project-card p {
color: var(--text-secondary);
margin-bottom: var(--spacing-md);
line-height: 1.6;
}
.project-status {
display: inline-block;
padding: var(--spacing-xs) var(--spacing-sm);
background: rgba(0, 245, 255, 0.1);
color: var(--accent-primary);
border-radius: var(--radius-sm);
font-size: 0.8rem;
font-weight: 500;
font-family: var(--font-mono);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.project-status.active {
background: rgba(34, 197, 94, 0.1);
color: #22c55e;
}
.project-status.development {
background: rgba(249, 115, 22, 0.1);
color: #f97316;
}
/* Team */
.team-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: var(--spacing-lg);
margin-top: var(--spacing-lg);
}
.team-member {
background: var(--bg-card);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-lg);
padding: var(--spacing-lg);
text-align: center;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.team-member:hover {
transform: translateY(-8px);
background: var(--bg-card-hover);
box-shadow: var(--shadow-xl);
border-color: var(--border-accent);
}
.member-avatar {
width: 120px;
height: 120px;
background: var(--accent-gradient);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 2.5rem;
color: var(--bg-primary);
margin: 0 auto var(--spacing-md);
position: relative;
}
.member-avatar::after {
content: "";
position: absolute;
inset: 3px;
background: var(--bg-card);
border-radius: 50%;
z-index: 1;
}
.member-avatar i {
z-index: 2;
position: relative;
}
.team-member h3 {
font-size: 1.5rem;
font-weight: 600;
margin-bottom: var(--spacing-xs);
}
.team-role {
color: var(--accent-primary);
font-weight: 500;
margin-bottom: var(--spacing-sm);
font-family: var(--font-mono);
font-size: 0.9rem;
}
.team-member p {
color: var(--text-secondary);
line-height: 1.6;
}
/* About Section */
.about-content {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
.about-content p {
font-size: 1.125rem;
color: var(--text-secondary);
margin-bottom: var(--spacing-lg);
line-height: 1.7;
text-align: left;
}
.about-content p:last-child {
margin-bottom: 0;
}
/* Vision Section */
.vision-content {
max-width: 1000px;
margin: 0 auto;
}
.vision-text {
text-align: center;
margin-bottom: var(--spacing-2xl);
}
.vision-text p {
font-size: 1.125rem;
color: var(--text-secondary);
line-height: 1.7;
max-width: 700px;
margin: 0 auto;
}
.principles-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
gap: var(--spacing-lg);
}
.principle-card {
background: var(--bg-card);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-lg);
padding: var(--spacing-lg);
text-align: center;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.principle-card:hover {
transform: translateY(-5px);
background: var(--bg-card-hover);
box-shadow: var(--shadow-lg);
border-color: var(--border-accent);
}
.principle-icon {
display: flex;
align-items: center;
justify-content: center;
width: 80px;
height: 80px;
background: var(--accent-gradient);
border-radius: 50%;
margin: 0 auto var(--spacing-md);
font-size: 1.8rem;
color: var(--bg-primary);
}
.principle-card h4 {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: var(--spacing-sm);
color: var(--text-primary);
}
.principle-card p {
color: var(--text-secondary);
line-height: 1.6;
}
/* Contact Section */
.contact-container {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--spacing-2xl);
max-width: 1000px;
margin: 0 auto;
}
.contact-methods {
display: flex;
flex-direction: column;
gap: var(--spacing-lg);
}
.contact-item {
display: flex;
align-items: flex-start;
gap: var(--spacing-sm);
}
.contact-icon {
display: flex;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
background: var(--accent-gradient);
border-radius: var(--radius-md);
font-size: 1.2rem;
color: var(--bg-primary);
flex-shrink: 0;
}
.contact-details h4 {
font-size: 1.1rem;
font-weight: 600;
margin-bottom: var(--spacing-xs);
color: var(--text-primary);
}
.contact-details a {
color: var(--text-secondary);
transition: color 0.3s ease;
}
.contact-details a:hover {
color: var(--accent-primary);
}
/* Contact Form */
.contact-form {
background: var(--bg-card);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-lg);
padding: var(--spacing-xl);
}
.form-group {
margin-bottom: var(--spacing-md);
}
.form-group label {
display: block;
margin-bottom: var(--spacing-xs);
font-weight: 500;
color: var(--text-primary);
font-size: 0.9rem;
}
.form-group input,
.form-group select,
.form-group textarea {
width: 100%;
padding: var(--spacing-sm);
background: var(--bg-tertiary);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-md);
color: var(--text-primary);
font-size: 0.95rem;
font-family: var(--font-primary);
transition: all 0.3s ease;
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
outline: none;
border-color: var(--accent-primary);
box-shadow: 0 0 0 3px rgba(0, 245, 255, 0.1);
}
.form-group textarea {
resize: vertical;
min-height: 120px;
font-family: var(--font-primary);
}
.form-group select {
cursor: pointer;
}
.contact-form .btn {
width: 100%;
justify-content: center;
margin-top: var(--spacing-sm);
}
/* Footer */
.footer {
background: var(--bg-secondary);
border-top: 1px solid var(--border-subtle);
padding: var(--spacing-2xl) 0 var(--spacing-lg);
}
.footer-content {
display: grid;
grid-template-columns: 2fr 1fr 1fr 1fr;
gap: var(--spacing-xl);
margin-bottom: var(--spacing-xl);
}
.footer-brand .logo {
font-size: 1.5rem;
margin-bottom: var(--spacing-sm);
display: block;
}
.footer-brand p {
color: var(--text-secondary);
margin-bottom: var(--spacing-lg);
line-height: 1.6;
max-width: 300px;
}
.footer-social {
display: flex;
gap: var(--spacing-sm);
}
.social-link {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
background: var(--bg-card);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-md);
color: var(--text-secondary);
font-size: 1.1rem;
transition: all 0.3s ease;
}
.social-link:hover {
background: var(--accent-gradient);
color: var(--bg-primary);
transform: translateY(-2px);
border-color: transparent;
}
.footer-links h4 {
font-size: 1.1rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: var(--spacing-sm);
}
.footer-links ul {
display: flex;
flex-direction: column;
gap: var(--spacing-xs);
}
.footer-links a {
color: var(--text-secondary);
font-size: 0.9rem;
transition: color 0.3s ease;
}
.footer-links a:hover {
color: var(--accent-primary);
}
.footer-bottom {
border-top: 1px solid var(--border-subtle);
padding-top: var(--spacing-lg);
}
.footer-bottom-content {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: var(--spacing-sm);
}
.footer-bottom p {
color: var(--text-muted);
font-size: 0.9rem;
}
.footer-badges {
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.badge {
display: flex;
align-items: center;
gap: var(--spacing-xs);
padding: var(--spacing-xs) var(--spacing-sm);
background: var(--bg-card);
border: 1px solid var(--border-subtle);
border-radius: var(--radius-sm);
font-size: 0.8rem;
color: var(--text-muted);
}
.badge i {
color: var(--accent-primary);
}
/* Responsive Design */
@media (max-width: 1024px) {
.nav-container {
padding: 0 var(--spacing-md);
}
.container {
padding: 0 var(--spacing-md);
}
.footer-content {
grid-template-columns: 1fr 1fr;
gap: var(--spacing-lg);
}
.contact-container {
grid-template-columns: 1fr;
gap: var(--spacing-xl);
}
}
@media (max-width: 768px) {
.mobile-menu-btn {
display: block;
}
.nav-links {
display: none;
position: absolute;
top: 100%;
left: 0;
width: 100%;
background: var(--bg-secondary);
border-top: 1px solid var(--border-subtle);
flex-direction: column;
padding: var(--spacing-lg);
}
.nav-links.active {
display: flex;
}
.nav-links a::after {
display: none;
}
.hero h1 {
font-size: clamp(2rem, 8vw, 3rem);
}
.hero p {
font-size: 1.1rem;
}
.hero-buttons {
flex-direction: column;
align-items: center;
}
.section {
padding: 4rem 0;
}
.projects-grid {
grid-template-columns: 1fr;
}
.team-grid {
grid-template-columns: 1fr;
}
.principles-grid {
grid-template-columns: 1fr;
}
.footer-content {
grid-template-columns: 1fr;
text-align: center;
gap: var(--spacing-lg);
}
.footer-brand p {
max-width: none;
}
.footer-social {
justify-content: center;
}
.footer-bottom-content {
flex-direction: column;
text-align: center;
gap: var(--spacing-sm);
}
}
@media (max-width: 480px) {
.container {
padding: 0 var(--spacing-sm);
}
.nav-container {
padding: 0 var(--spacing-sm);
}
.hero-content {
padding: var(--spacing-sm) 0;
}
.project-card,
.team-member,
.principle-card,
.contact-form {
padding: var(--spacing-md);
}
.section-header {
margin-bottom: var(--spacing-xl);
}
.contact-form {
padding: var(--spacing-lg);
}
}
/* Animations and Interactions */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
.star {
animation: none;
}
}
/* Print Styles */
@media print {
.animated-bg,
.stars,
nav,
.hero-buttons,
.contact-form,
.footer-social {
display: none;
}
body {
background: white;
color: black;
}
.section {
padding: 2rem 0;
}
}

View file

@ -1,432 +0,0 @@
/*
interstellar_development website
Copyright (C) 2024 interstellar_development
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
:root {
--background-color: #0b0c1d;
--text-color: #c7d5e0;
--accent-color: #ffdd55;
--accent-hover-color: #ffd700;
--dark-blue: rgba(31, 42, 64, 1);
--dark-blue-translucent: rgba(31, 42, 64, 0.9);
--light-blue: rgba(46, 58, 95, 0.8);
--border-radius: 8px;
--transition-speed: 0.3s;
--box-shadow: 0 2px 15px rgba(0, 0, 0, 0.7);
--font-size-large: 2.5em;
--font-size-medium: 1.8em;
}
/* Reset and normalize */
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* Body styling */
body {
background-color: var(--background-color);
color: var(--text-color);
font-family: "Arial", sans-serif;
line-height: 1.6;
padding: 0 20px;
background: url("images/star.jpg") no-repeat center center fixed;
background-size: cover;
}
/* Header Styling */
/* Header Styling */
header {
background-color: var(--dark-blue);
height: 5em;
position: fixed;
width: 100%;
top: 0;
left: 0;
padding: 15px 20px;
box-shadow: var(--box-shadow);
backdrop-filter: blur(5px);
z-index: 100;
margin-bottom: 0px;
}
/* Burger Menu Styling */
.burger-menu {
background: none;
border: none;
color: #ffffff;
font-size: 1.8em;
cursor: pointer;
display: block;
padding: 0;
z-index: 110;
}
/* Dropdown Menu (Hidden by Default) */
.div-menu {
z-index: 1;
background-color: var(--light-blue);
width: 100%;
position: fixed;
top: 0;
left: 0;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
padding: 0;
margin-top: 0px;
height: auto;
}
.div-menu li {
margin: 0;
padding: 1em;
z-index: 1;
}
.div-menu a {
width: 100%;
padding: 8px 0;
text-align: center;
color: #ffffff;
text-decoration: none;
border-radius: 5px;
transition: background-color 0.3s ease;
display: block;
}
.div-menu a:hover {
background-color: #34495e;
}
/* Menu Animation and Styling */
.menu {
display: flex;
flex-direction: column;
background-color: var(--light-blue);
position: absolute;
top: -50vh;
left: 0;
width: 100%;
z-index: 5;
padding: 0;
margin: 0;
list-style: none;
justify-content: center;
text-align: center;
font-weight: bolder;
font-size: large;
transition: top 0.5s ease-in-out;
}
.menu.active {
display: flex;
top: 4em;
z-index: 5;
}
/* Header Content Container */
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
z-index: 10;
}
/* Project Name Styling */
.project-name {
font-size: 2em;
color: var(--accent-color);
text-decoration: none;
transition: color var(--transition-speed), text-shadow var(--transition-speed);
}
.project-name:hover {
color: var(--accent-hover-color);
text-shadow: 0 0 10px var(--accent-hover-color);
}
/* Article styling */
article {
max-width: 800px;
margin: 6.25em auto;
padding: 20px;
background-color: var(--dark-blue-translucent);
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
backdrop-filter: blur(5px);
}
article h1 {
font-size: var(--font-size-large);
margin-bottom: 20px;
color: var(--accent-color);
text-shadow: 0 0 15px var(--accent-color);
}
article p {
color: var(--text-color);
margin-bottom: 20px;
hyphens: auto;
}
/* Download list */
article h2 {
font-size: var(--font-size-medium);
margin: 20px 0 10px;
color: var(--accent-color);
text-shadow: 0 0 10px var(--accent-color);
}
article ul {
list-style-type: none;
padding: 0;
}
article ul a li {
background-color: var(--light-blue);
margin-bottom: 10px;
border-radius: var(--border-radius);
padding: 10px;
transition: background-color var(--transition-speed),
box-shadow var(--transition-speed);
}
article ul a li:hover {
background-color: rgba(68, 80, 124, 0.9);
box-shadow: 0 0 10px var(--accent-color);
}
article ul a li {
text-decoration: none;
color: var(--accent-color);
font-weight: bold;
}
/* Footer styling */
footer {
background-color: var(--dark-blue);
padding: 10px 20px;
color: var(--text-color);
width: 100%;
position: fixed;
bottom: 0;
left: 0;
box-shadow: 0 -2px 15px rgba(0, 0, 0, 0.7);
backdrop-filter: blur(5px);
}
.footer-content {
text-align: center;
font-size: 0.9em;
}
/* Card container styles */
.cards {
display: grid;
grid-template-columns: repeat(3, 1fr); /* Display 3 cards per line */
gap: 20px;
margin-top: 50px;
}
/* Ensure the <a> tag covers the entire card */
section .card a {
display: flex; /* Use flex to make <a> fill the card and align content */
flex-direction: column;
justify-content: center; /* Vertically center the content */
align-items: center; /* Horizontally center the content */
text-decoration: none;
color: inherit;
height: 100%;
width: 100%;
padding: 20px;
}
/* Card styles */
section .card {
text-align: center;
list-style: none;
background: linear-gradient(
180deg,
rgba(0, 0, 50, 0.9),
rgba(10, 10, 100, 0.9),
rgba(30, 30, 150, 0.9)
);
border-radius: 12px;
box-shadow: 0 5px 20px rgba(0, 0, 50, 0.8), 0 0 10px rgba(255, 255, 255, 0.1);
border: 1px solid #2e3a60;
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: space-between;
transition: background 0.5s ease, transform 0.4s ease, box-shadow 0.5s ease;
}
/* Hover effect */
section .card:hover {
transform: translateY(-8px);
background: linear-gradient(
180deg,
rgba(30, 30, 150, 0.9),
rgba(40, 0, 100, 0.9),
rgba(100, 0, 150, 0.9)
);
box-shadow: 0 10px 30px rgba(0, 0, 100, 0.7), 0 0 20px rgba(255, 221, 85, 0.8);
}
section .card img {
height: 80px;
width: 80px;
object-fit: cover;
border-radius: 50%;
margin: 0 auto 15px;
box-shadow: 0 0 15px rgba(255, 221, 85, 0.5);
}
section .card h3 {
margin: 10px 0;
font-size: 1.4em;
font-weight: bold;
color: rgba(255, 221, 85, 1);
text-shadow: 0 0 15px rgba(255, 221, 85, 0.9);
}
section .card p {
flex-grow: 1;
color: rgba(200, 220, 255, 0.8);
margin-bottom: 10px;
text-shadow: 0 0 8px rgba(255, 255, 255, 0.2);
}
section .card::before {
content: "";
position: absolute;
top: -20px;
right: -20px;
width: 60px;
height: 60px;
border-radius: 50%;
background: radial-gradient(
circle,
rgba(255, 255, 255, 0.1),
rgba(255, 255, 255, 0.02)
);
box-shadow: 0 0 50px rgba(255, 255, 255, 0.5);
animation: spin 8s linear infinite;
}
section .card .suit-icon {
position: absolute;
bottom: 10px;
right: 10px;
width: 24px;
height: 24px;
opacity: 0.7;
transition: opacity var(--transition-speed);
}
section .card:hover .suit-icon {
opacity: 1;
}
/* Keyframes for spinning element */
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* Form styling */
form {
max-width: 600px;
margin: 0 auto;
background: var(--dark-blue-translucent);
padding: 20px;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
backdrop-filter: blur(5px);
}
form label,
form input,
form textarea {
color: var(--text-color);
background-color: var(--light-blue);
border: 1px solid #3a4b7f;
border-radius: var(--border-radius);
padding: 10px;
margin: 10px 0;
width: 100%;
}
form input[type="submit"] {
background-color: var(--accent-color);
color: #fff;
border: none;
cursor: pointer;
transition: background-color var(--transition-speed);
}
form input[type="submit"]:hover {
background-color: var(--accent-hover-color);
}
/* Footer Styling */
footer {
background-color: var(--dark-blue);
padding: 10px 20px;
color: var(--text-color);
text-align: center;
font-size: 0.9em;
}
@media (max-width: 768px) {
.cards {
grid-template-columns: 1fr; /* 1 card per line on smaller screens */
}
header ul {
flex-direction: column;
gap: 10px;
}
article {
margin: 12em 10px;
padding: 15px;
}
section .card {
padding: 12px;
}
section .card img {
height: 60px;
width: 60px;
}
.project-name {
font-size: 1.3em;
}
}

View file

@ -1,110 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Game Collection</title>
<link rel="stylesheet" href="styles.css" />
<link
rel="apple-touch-icon"
sizes="180x180"
href="../favicon_io/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="../favicon_io/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="../favicon_io/favicon-16x16.png"
/>
<link rel="manifest" href="../favicon_io/site.webmanifest" />
</head>
<body>
<header>
<h1>Game Collection</h1>
</header>
<main>
<div class="grid-container">
<a href="" target="_blank" class="item">
<img
src="../secret/../secret/images/default.jpeg"
alt="Image can't be displayed"
/>
<h2>Snake</h2>
<div class="description">
<p>
Guide the snake to eat food and grow longer while avoiding
collisions with the walls and itself.
</p>
</div>
</a>
<a href="" target="_blank" class="item">
<img
src="../secret/images/default.jpeg"
alt="Image can't be displayed"
/>
<h2>Solitaire</h2>
<div class="description">
<p>
A classic card game where the objective is to move all cards to
foundation piles in ascending order.
</p>
</div>
</a>
<a href="../secret/mineSweeper/index.html" target="_blank" class="item">
<img
src="../secret/images/minesweeper.png"
alt="Image can't be displayed"
/>
<h2>Minesweeper</h2>
<div class="description">
<p>
Uncover squares on a grid while avoiding hidden mines, using
numbers to deduce safe spots.
</p>
</div>
</a>
<a
href="../secret/guessMyNumber/index.html"
target="_blank"
class="item"
>
<img
src="../secret/images/number.jpeg"
alt="Image can't be displayed"
/>
<h2>Guess My Number</h2>
<div class="description">
<p>
A simple game where you try to guess a randomly chosen number
within a certain range.
</p>
</div>
</a>
<a href="" target="_blank" class="item">
<img
src="../secret/images/default.jpeg"
alt="Image can't be displayed"
/>
<h2>Endless Runner</h2>
<div class="description">
<p>
Run through an endless landscape, avoiding obstacles and
collecting items to score points.
</p>
</div>
</a>
</div>
</main>
<footer>
<p>&copy; 2025 Game Collection</p>
</footer>
</body>
</html>

View file

@ -1,120 +0,0 @@
/* Reset and box-sizing */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* General Styles */
body {
font-family: Arial, sans-serif;
background-color: #282c34;
color: #ffffff;
margin: 0;
}
header {
background-color: #4caf50;
color: white;
text-align: center;
padding: 1em 0;
font-size: 1.5rem;
}
footer {
background-color: #333;
color: white;
text-align: center;
padding: 1em 0;
margin-top: 20px;
}
/* Grid Styles */
.grid-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px; /* Space between items */
padding: 20px; /* Space around the grid */
}
/* Game Item */
.item {
position: relative;
background-color: #444;
border-radius: 10px;
overflow: hidden;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
transition: transform 0.3s ease, box-shadow 0.3s ease, filter 0.3s ease;
width: 100%; /* Ensure it takes full width of the column */
height: 400px; /* Set a fixed height for all items */
display: flex;
flex-direction: column; /* Stack children vertically */
}
/* Ensure the image takes the top part of the card */
.item img {
width: 100%;
height: 100%; /* Set a height for the image */
object-fit: cover;
}
.item .description {
padding: 30px;
font-size: 1rem;
color: #ddd;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 0 0 10px 10px;
flex-grow: 1; /* Allow description to take remaining space */
}
p {
text-decoration: none;
}
/* Hover effect for scaling and glowing */
.item:hover {
transform: scale(1.05);
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4);
filter: brightness(1.2);
}
.item:hover img {
transform: scale(1.1); /* Slight zoom-in effect for the image */
filter: brightness(1.1); /* Increase image brightness */
}
.item h2 {
position: absolute;
top: 10%;
left: 50%;
transform: translateX(-50%);
color: white;
font-size: 1.5rem;
background-color: rgba(0, 0, 0, 0.6);
padding: 5px 15px;
border-radius: 5px;
text-align: center;
opacity: 0;
transition: opacity 0.3s ease, transform 0.3s ease;
}
.item:hover h2 {
opacity: 1;
transform: translateX(-50%) translateY(-10px); /* Move the title upwards with hover */
}
/* Mobile Optimization */
@media (max-width: 600px) {
header {
font-size: 1.2rem;
}
.item {
height: auto; /* Allow auto height on mobile for better responsiveness */
width: auto;
}
.grid-container {
grid-template-columns: repeat(1, 1fr);
}
}