diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 40b878d..0000000 --- a/.gitignore +++ /dev/null @@ -1 +0,0 @@ -node_modules/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..1dda9bb --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# pages + diff --git a/dropdown.js b/dropdown.js new file mode 100644 index 0000000..fc97817 --- /dev/null +++ b/dropdown.js @@ -0,0 +1,61 @@ +// @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 . + */ +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 diff --git a/favicon_io/about.txt b/favicon_io/about.txt new file mode 100644 index 0000000..2062908 --- /dev/null +++ b/favicon_io/about.txt @@ -0,0 +1,6 @@ +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/) diff --git a/favicon_io/android-chrome-192x192.png b/favicon_io/android-chrome-192x192.png new file mode 100644 index 0000000..385d40d Binary files /dev/null and b/favicon_io/android-chrome-192x192.png differ diff --git a/favicon_io/android-chrome-512x512.png b/favicon_io/android-chrome-512x512.png new file mode 100644 index 0000000..843853f Binary files /dev/null and b/favicon_io/android-chrome-512x512.png differ diff --git a/favicon_io/apple-touch-icon.png b/favicon_io/apple-touch-icon.png new file mode 100644 index 0000000..1b41da6 Binary files /dev/null and b/favicon_io/apple-touch-icon.png differ diff --git a/favicon_io/favicon-16x16.png b/favicon_io/favicon-16x16.png new file mode 100644 index 0000000..870d85f Binary files /dev/null and b/favicon_io/favicon-16x16.png differ diff --git a/favicon_io/favicon-32x32.png b/favicon_io/favicon-32x32.png new file mode 100644 index 0000000..89bbbad Binary files /dev/null and b/favicon_io/favicon-32x32.png differ diff --git a/favicon_io/favicon.ico b/favicon_io/favicon.ico new file mode 100644 index 0000000..385d320 Binary files /dev/null and b/favicon_io/favicon.ico differ diff --git a/favicon_io/site.webmanifest b/favicon_io/site.webmanifest new file mode 100644 index 0000000..45dc8a2 --- /dev/null +++ b/favicon_io/site.webmanifest @@ -0,0 +1 @@ +{"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"} \ No newline at end of file diff --git a/footer.js b/footer.js new file mode 100644 index 0000000..3aed36c --- /dev/null +++ b/footer.js @@ -0,0 +1,68 @@ +// @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 . + */ + +class Footer extends HTMLElement { + constructor() { + super(); + } + + connectedCallback() { + this.innerHTML = ` +
+
+ +
+
+ `; + + // 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 diff --git a/header.js b/header.js new file mode 100644 index 0000000..6cb9811 --- /dev/null +++ b/header.js @@ -0,0 +1,46 @@ +// @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 . + */ +class Header extends HTMLElement { + constructor() { + super(); + } + + connectedCallback() { + this.innerHTML = ` +
+ +
+ + `; + } +} + +customElements.define("header-component", Header); +// @license-end diff --git a/src/images/Patrick.png b/images/Patrick.png similarity index 100% rename from src/images/Patrick.png rename to images/Patrick.png diff --git a/images/nicolas.png b/images/nicolas.png new file mode 100644 index 0000000..63b6bf3 Binary files /dev/null and b/images/nicolas.png differ diff --git a/src/images/sage.png b/images/sage.png similarity index 100% rename from src/images/sage.png rename to images/sage.png diff --git a/images/star.jpg b/images/star.jpg new file mode 100644 index 0000000..2b1475a Binary files /dev/null and b/images/star.jpg differ diff --git a/index.html b/index.html index a81af8f..f9b4677 100644 --- a/index.html +++ b/index.html @@ -1,496 +1,233 @@ + + - Interstellar Development | Free and Open Source Software - - - - - - - - - + + + + + + Interstellar Development - -
-
+ + - - -
- -
-
-
-

- Advancing Free Software Development -

+
    +
  • +

    Previously we had more unfinished Games listed here.

    - We develop high-quality free and open source software solutions, - with a focus on gaming and applications that respect user freedom. + We decided against displaying them and giving people the + impression we are working on them currently.

    - -
-
+

In the Future we will display the released games here

+ + + +

Our Other Projects

+
- -
-
-
-

Our Projects

-

- High-quality free software solutions built with passion and - dedication -

-
- - -
-
- - - - -
- -
- -
- -
- -
-
-
-
- - -
-
-
-

Our Team

-

- A small but dedicated international team committed to free - software -

-
- -
-
-
- -
-

Patrick

-
- Lead Programmer & System Administrator -
-

- Patrick focuses on backend development and system - administration, managing our infrastructure and core application - logic with expertise in server-side technologies and DevOps. -

-
- -
-
- -
-

Sage

-
Frontend Developer & Communications
-

- 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. -

-
-
-
-
- - -
-
-
-

About Us

-
- -
+ +

Our Team

+
+ + + +
- -
-
-
-

Our Vision

-
- -
-
-

- 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. -

-
- -
-
-
- -
-

Software Freedom

-

- All our projects are released under copyleft licenses to - ensure user freedoms are protected and preserved. -

-
- -
-
- -
-

Community Collaboration

-

- We believe in building software with and for the community, - welcoming contributions and feedback. -

-
- -
-
- -
-

Quality Standards

-

- We strive to create software that matches or exceeds the - quality of proprietary alternatives. -

-
-
-
-
+ +
+

About Us

+

+ Welcome to Interstellar Development! We are a small, passionate + international team dedicated to transforming the programming world + into a free-and-open-source future. Our diverse backgrounds and + experiences fuel our commitment to creating free and open-source + software, particularly in the realm of gaming. +

+

+ Our journey began with a shared vision: to better organize our efforts + in making free and open-source games more efficient and accessible. We + recognized that many current free software games are either lacking in + quality or simply do not exist. This realization inspired us to focus + on developing games that are unplayable on GNU/Linux and FreeBSD + systems, as well as creating free software alternatives for those in + need. +

+

+ At Interstellar Development, we believe that true freedom for computer + users can only be achieved through the use of free software. That’s + why we are committed to licensing all of our projects under copyleft + free and open-source software licenses, ensuring that our games remain + free for everyone to enjoy, forever. +

+

+ While we are not currently accepting donations, we welcome your + support in the form of feedback and suggestions for improvements. If + you wish to contribute financially, we encourage you to donate to the + Free Software Foundation, as without them, we would have never started + this. +

+

+ Join us as we strive to create a vibrant community around free + software and gaming. Together, we can make a difference and pave the + way for a free future! +

- -
-
-
-
-
0
-
Projects
-
-
-
0
-
Team Members
-
-
-
0
-
Years Active
-
-
-
0
-
% Free Software
-
-
-
+
+

Our Vision

+

Interstellar Development: Free Software is Our Passion

+

+ At Interstellar Development, we embarked on this journey to create a + more organized and efficient approach to developing free and + open-source software, with a particular focus on gaming. We recognized + a significant gap in the availability and quality of free software + games, which often fail to meet the expectations of users or simply do + not exist. Our mission is to fill this void and elevate the standards + of free gaming experiences. +

+

+ 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. +

+

+ 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. +

+

+ 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. +

+

+ 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. +

+

+ 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! +

+ - -
-
-
-

Get In Touch

-

- Have questions about our projects or want to contribute? We'd love - to hear from you. -

-
- -
-
-
-
-
- -
- -
- -
-
- -
-
-

Source Code

- View Our Projects -
-
-
-
- -
-
- - -
- -
- - -
- -
- - -
- -
- - -
- - -
-
-
-
- - - -
- - - - - - - - - - - - + + diff --git a/secret/asteroidDestroyer/explenation.html b/secret/asteroidDestroyer/explenation.html new file mode 100644 index 0000000..843c32c --- /dev/null +++ b/secret/asteroidDestroyer/explenation.html @@ -0,0 +1,47 @@ + + + + + + Game Landing Page + + + + + + + +
+
+ + +
+ +
+

Welcome to the Asteroid Game!

+

+ In this game, you control a spaceship that shoots at asteroids to + avoid destruction and collect items for power-ups. +

+

Your goal is to survive as long as possible while scoring points!

+ +
+
+ + + + diff --git a/secret/asteroidDestroyer/game.js b/secret/asteroidDestroyer/game.js new file mode 100644 index 0000000..2ea6461 --- /dev/null +++ b/secret/asteroidDestroyer/game.js @@ -0,0 +1,414 @@ +"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); diff --git a/secret/asteroidDestroyer/secret.html b/secret/asteroidDestroyer/secret.html new file mode 100644 index 0000000..1b22d19 --- /dev/null +++ b/secret/asteroidDestroyer/secret.html @@ -0,0 +1,41 @@ + + + + + + Asteroid Shooter + + + + + + + + + + +
+ + + +
+ + + + diff --git a/secret/asteroidDestroyer/style.css b/secret/asteroidDestroyer/style.css new file mode 100644 index 0000000..e90a6ad --- /dev/null +++ b/secret/asteroidDestroyer/style.css @@ -0,0 +1,43 @@ +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; + } +} diff --git a/secret/asteroidDestroyer/styles.css b/secret/asteroidDestroyer/styles.css new file mode 100644 index 0000000..7d92d64 --- /dev/null +++ b/secret/asteroidDestroyer/styles.css @@ -0,0 +1,76 @@ +* { + 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; +} diff --git a/secret/endlessRunner/index.html b/secret/endlessRunner/index.html new file mode 100644 index 0000000..c2feb26 --- /dev/null +++ b/secret/endlessRunner/index.html @@ -0,0 +1,33 @@ + + + + + + Endless runner + + + + + + +
+ + +
+ + + diff --git a/secret/endlessRunner/script.js b/secret/endlessRunner/script.js new file mode 100644 index 0000000..59df696 --- /dev/null +++ b/secret/endlessRunner/script.js @@ -0,0 +1,90 @@ +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 ( +
+ + {!running && ( + + )} +
+ ); +} diff --git a/secret/endlessRunner/styles.css b/secret/endlessRunner/styles.css new file mode 100644 index 0000000..b8850fc --- /dev/null +++ b/secret/endlessRunner/styles.css @@ -0,0 +1,34 @@ +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; +} diff --git a/secret/game.js b/secret/game.js new file mode 100644 index 0000000..36185f6 --- /dev/null +++ b/secret/game.js @@ -0,0 +1,404 @@ +"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(); diff --git a/secret/guessMyNumber/game.js b/secret/guessMyNumber/game.js new file mode 100644 index 0000000..9a3436d --- /dev/null +++ b/secret/guessMyNumber/game.js @@ -0,0 +1,65 @@ +"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(); diff --git a/secret/guessMyNumber/index.html b/secret/guessMyNumber/index.html new file mode 100644 index 0000000..4e88eaa --- /dev/null +++ b/secret/guessMyNumber/index.html @@ -0,0 +1,72 @@ + + + + + + Guess My Number + + + + + + + +
+ +
+
+

Guess My Number - Game

+

+
+ +
+

+

+ +
+

Description

+

Guess a number between 1 and 20

+

A = check

+

B = Reload

+

▲ = increases guess by one

+

▼ = decreases guess by one

+
+
+
+ + +
+ +
+ + +
+ + +
+ + +
+ + +
+
+
+ + + + diff --git a/secret/guessMyNumber/styles.css b/secret/guessMyNumber/styles.css new file mode 100644 index 0000000..3a50aec --- /dev/null +++ b/secret/guessMyNumber/styles.css @@ -0,0 +1,189 @@ +/* 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); +} diff --git a/secret/guessMyNumber/styles.js b/secret/guessMyNumber/styles.js new file mode 100644 index 0000000..8ccae52 --- /dev/null +++ b/secret/guessMyNumber/styles.js @@ -0,0 +1,148 @@ +"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(); diff --git a/secret/images/asteroid.png b/secret/images/asteroid.png new file mode 100644 index 0000000..2859780 Binary files /dev/null and b/secret/images/asteroid.png differ diff --git a/secret/images/background.jpg b/secret/images/background.jpg new file mode 100644 index 0000000..63f85fe Binary files /dev/null and b/secret/images/background.jpg differ diff --git a/secret/images/blackjack.jpg b/secret/images/blackjack.jpg new file mode 100644 index 0000000..b20ee37 Binary files /dev/null and b/secret/images/blackjack.jpg differ diff --git a/secret/images/default.jpeg b/secret/images/default.jpeg new file mode 100644 index 0000000..610df27 Binary files /dev/null and b/secret/images/default.jpeg differ diff --git a/secret/images/endless_runner.png b/secret/images/endless_runner.png new file mode 100644 index 0000000..5d153d7 Binary files /dev/null and b/secret/images/endless_runner.png differ diff --git a/secret/images/minesweeper.png b/secret/images/minesweeper.png new file mode 100644 index 0000000..e7d7376 Binary files /dev/null and b/secret/images/minesweeper.png differ diff --git a/secret/images/number.jpeg b/secret/images/number.jpeg new file mode 100644 index 0000000..c6dbdd3 Binary files /dev/null and b/secret/images/number.jpeg differ diff --git a/secret/images/snake.png b/secret/images/snake.png new file mode 100644 index 0000000..572f201 Binary files /dev/null and b/secret/images/snake.png differ diff --git a/secret/images/solitaire.png b/secret/images/solitaire.png new file mode 100644 index 0000000..6393bde Binary files /dev/null and b/secret/images/solitaire.png differ diff --git a/secret/index.html b/secret/index.html new file mode 100644 index 0000000..dc45d69 --- /dev/null +++ b/secret/index.html @@ -0,0 +1,118 @@ + + + + + + Secret Game Collection + + + + + + + +
+

Secret Game Collection

+
+ +
+ +
+ +
+

© 2025 Game Collection

+
+ + diff --git a/secret/mineSweeper/index.html b/secret/mineSweeper/index.html new file mode 100644 index 0000000..5794679 --- /dev/null +++ b/secret/mineSweeper/index.html @@ -0,0 +1,60 @@ + + + + + + Minesweeper + + + + + + + + +
+

Minesweeper

+ + + + + + + +
+ +
+ +
+ + + + diff --git a/secret/mineSweeper/script.js b/secret/mineSweeper/script.js new file mode 100644 index 0000000..f30f685 --- /dev/null +++ b/secret/mineSweeper/script.js @@ -0,0 +1,192 @@ +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); + }); +}; diff --git a/secret/mineSweeper/styles.css b/secret/mineSweeper/styles.css new file mode 100644 index 0000000..8468965 --- /dev/null +++ b/secret/mineSweeper/styles.css @@ -0,0 +1,104 @@ +* { + 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; + } +} diff --git a/secret/snake/audio/dead.mp3 b/secret/snake/audio/dead.mp3 new file mode 100644 index 0000000..414bf65 Binary files /dev/null and b/secret/snake/audio/dead.mp3 differ diff --git a/secret/snake/audio/down.mp3 b/secret/snake/audio/down.mp3 new file mode 100644 index 0000000..03533a0 Binary files /dev/null and b/secret/snake/audio/down.mp3 differ diff --git a/secret/snake/audio/eat.mp3 b/secret/snake/audio/eat.mp3 new file mode 100644 index 0000000..076198c Binary files /dev/null and b/secret/snake/audio/eat.mp3 differ diff --git a/secret/snake/audio/left.mp3 b/secret/snake/audio/left.mp3 new file mode 100644 index 0000000..4d3d245 Binary files /dev/null and b/secret/snake/audio/left.mp3 differ diff --git a/secret/snake/audio/right.mp3 b/secret/snake/audio/right.mp3 new file mode 100644 index 0000000..64408ea Binary files /dev/null and b/secret/snake/audio/right.mp3 differ diff --git a/secret/snake/audio/up.mp3 b/secret/snake/audio/up.mp3 new file mode 100644 index 0000000..97cfbe9 Binary files /dev/null and b/secret/snake/audio/up.mp3 differ diff --git a/secret/snake/game.js b/secret/snake/game.js new file mode 100644 index 0000000..f94dc2e --- /dev/null +++ b/secret/snake/game.js @@ -0,0 +1,95 @@ +"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); diff --git a/secret/snake/img/food.png b/secret/snake/img/food.png new file mode 100644 index 0000000..921fe78 Binary files /dev/null and b/secret/snake/img/food.png differ diff --git a/secret/snake/img/ground.png b/secret/snake/img/ground.png new file mode 100644 index 0000000..218b190 Binary files /dev/null and b/secret/snake/img/ground.png differ diff --git a/secret/snake/index.html b/secret/snake/index.html new file mode 100644 index 0000000..7f81ed2 --- /dev/null +++ b/secret/snake/index.html @@ -0,0 +1,67 @@ + + + + + + Snake - Game + + + + + + + +
+ +
+
+

Snake - Game

+
+

Description

+

Eat as many apples and grow as much as possible

+

◀ or A or arrow left = move left

+

▶ or D or arrow right = move right

+

▲ or W or arrow up = move up

+

▼ or S or arrow down = move down

+
+ +
+
+ + +
+ +
+ + +
+ + +
+ + +
+ + + +
+
+
+ + + + diff --git a/secret/snake/styles.css b/secret/snake/styles.css new file mode 100644 index 0000000..2454d67 --- /dev/null +++ b/secret/snake/styles.css @@ -0,0 +1,238 @@ +/* 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; +} diff --git a/secret/snake/styles.js b/secret/snake/styles.js new file mode 100644 index 0000000..231d5b3 --- /dev/null +++ b/secret/snake/styles.js @@ -0,0 +1,134 @@ +"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(); diff --git a/secret/snake/test.html b/secret/snake/test.html new file mode 100644 index 0000000..12a5cfb --- /dev/null +++ b/secret/snake/test.html @@ -0,0 +1,197 @@ + + + + + + Snake Game - GameBoy Style + + + +
+

Snake Game

+
+ +
+ +
+ + + + diff --git a/secret/styles.css b/secret/styles.css new file mode 100644 index 0000000..b25a85c --- /dev/null +++ b/secret/styles.css @@ -0,0 +1,145 @@ +* { + 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); + } +} diff --git a/src/favicon/android-chrome-192x192.png b/src/favicon/android-chrome-192x192.png deleted file mode 100644 index e636383..0000000 Binary files a/src/favicon/android-chrome-192x192.png and /dev/null differ diff --git a/src/favicon/android-chrome-512x512.png b/src/favicon/android-chrome-512x512.png deleted file mode 100644 index 65f6ef4..0000000 Binary files a/src/favicon/android-chrome-512x512.png and /dev/null differ diff --git a/src/favicon/apple-touch-icon.png b/src/favicon/apple-touch-icon.png deleted file mode 100644 index 42de221..0000000 Binary files a/src/favicon/apple-touch-icon.png and /dev/null differ diff --git a/src/favicon/favicon-16x16.png b/src/favicon/favicon-16x16.png deleted file mode 100644 index e736fae..0000000 Binary files a/src/favicon/favicon-16x16.png and /dev/null differ diff --git a/src/favicon/favicon-32x32.png b/src/favicon/favicon-32x32.png deleted file mode 100644 index 74501cd..0000000 Binary files a/src/favicon/favicon-32x32.png and /dev/null differ diff --git a/src/favicon/favicon.ico b/src/favicon/favicon.ico deleted file mode 100644 index 4de4913..0000000 Binary files a/src/favicon/favicon.ico and /dev/null differ diff --git a/src/js/animation/Meteor.js b/src/js/animation/Meteor.js deleted file mode 100644 index a141e80..0000000 --- a/src/js/animation/Meteor.js +++ /dev/null @@ -1,311 +0,0 @@ -class Meteor { - constructor(container) { - this.element = document.createElement("div"); - this.element.style.position = "absolute"; - this.container = container; - this.speed = Math.random() * 3 + 4; - this.life = 1.0; - this.particles = []; - - this.colorType = Math.floor(Math.random() * 4); - this.colors = this.getMeteorColors(); - - this.containerRect = container.getBoundingClientRect(); - - // Start from random edge with PIXEL-based positioning - const edge = Math.floor(Math.random() * 4); - switch (edge) { - case 0: - // Top - this.x = Math.random() * this.containerRect.width; - this.y = -20; - case 1: - // Right - this.x = this.containerRect.width + 20; - this.y = Math.random() * this.containerRect.height; - case 2: - // Bottom - this.x = Math.random() * this.containerRect.width; - this.y = this.containerRect.height + 20; - case 3: - // Left - this.x = -20; - this.y = Math.random() * this.containerRect.height; - default: - console.log("Error creating Meteor direction"); - } - - const centerX = this.containerRect.width / 2 + (Math.random() - 0.5) * 200; - const centerY = this.containerRect.height / 2 + (Math.random() - 0.5) * 200; - this.angle = - Math.atan2(centerY - this.y, centerX - this.x) + - (Math.random() - 0.5) * 0.8; - this.dx = Math.cos(this.angle) * this.speed; - this.dy = Math.sin(this.angle) * this.speed; - - this.init(); - } - - getMeteorColors() { - const colorSchemes = [ - { - head: "rgba(255, 255, 255, 1)", - core: "rgba(255, 230, 150, 0.9)", - mid: "rgba(255, 180, 80, 0.7)", - outer: "rgba(255, 100, 50, 0.5)", - glow: "rgba(255, 200, 100, 0.9)", - }, - { - head: "rgba(255, 255, 255, 1)", - core: "rgba(180, 220, 255, 0.9)", - mid: "rgba(100, 180, 255, 0.7)", - outer: "rgba(50, 100, 255, 0.5)", - glow: "rgba(100, 180, 255, 0.9)", - }, - { - head: "rgba(255, 255, 255, 1)", - core: "rgba(220, 180, 255, 0.9)", - mid: "rgba(200, 100, 255, 0.7)", - outer: "rgba(180, 50, 255, 0.5)", - glow: "rgba(200, 150, 255, 0.9)", - }, - { - head: "rgba(255, 255, 255, 1)", - core: "rgba(180, 255, 200, 0.9)", - mid: "rgba(80, 255, 150, 0.7)", - outer: "rgba(50, 200, 100, 0.5)", - glow: "rgba(150, 255, 180, 0.9)", - }, - ]; - return colorSchemes[this.colorType]; - } - - init() { - const size = Math.random() * 4 + 10; - const colors = this.colors; - - const head = document.createElement("div"); - head.style.width = `${size}px`; - head.style.height = `${size}px`; - head.style.borderRadius = "50%"; - head.style.background = ` - radial-gradient( - circle at 30% 30%, - ${colors.head} 0%, - ${colors.core} 30%, - ${colors.mid} 60%, - ${colors.outer} 100% - ) - `; - head.style.boxShadow = ` - 0 0 ${size * 4}px ${colors.glow}, - 0 0 ${size * 2}px rgba(255, 255, 255, 0.8), - inset 0 0 ${size * 0.5}px rgba(255, 255, 255, 0.9) - `; - head.style.position = "absolute"; - head.style.left = "50%"; - head.style.top = "50%"; - head.style.transform = "translate(-50%, -50%)"; - head.style.zIndex = "3"; - head.style.filter = "blur(0.5px)"; - - // Create multi-layer tail - this.createTailLayer(size * 3, size * 1.2, colors.core, 1, "1px"); - this.createTailLayer(size * 5, size * 2, colors.mid, 0.6, "2px"); - this.createTailLayer(size * 8, size * 3, colors.outer, 0.3, "3px"); - - // Assemble meteor - this.element.appendChild(head); - this.element.style.left = `${this.x}px`; - this.element.style.top = `${this.y}px`; - this.element.style.zIndex = "10"; - this.element.style.filter = "blur(0.5px)"; - - this.head = head; - this.size = size; - - this.container.appendChild(this.element); - - this.createTrailParticles(); - } - - createTailLayer(length, width, color, opacity, blur) { - const tail = document.createElement("div"); - const tailAngle = Math.atan2(this.dy, this.dx) + Math.PI; - - tail.style.width = `${length}px`; - tail.style.height = `${width}px`; - tail.style.position = "absolute"; - tail.style.left = "50%"; - tail.style.top = "50%"; - tail.style.transformOrigin = "left center"; - tail.style.transform = `translate(0, -50%) rotate(${tailAngle}rad)`; - tail.style.background = `linear-gradient(to right, - ${color} 0%, - ${color.replace(")", ", 0.8)").replace("rgba", "rgba")} 20%, - ${color.replace(")", ", 0.4)").replace("rgba", "rgba")} 50%, - ${color.replace(")", ", 0.1)").replace("rgba", "rgba")} 80%, - transparent 100%)`; - tail.style.opacity = opacity; - tail.style.filter = `blur(${blur})`; - tail.style.pointerEvents = "none"; - tail.style.zIndex = "2"; - tail.style.borderRadius = "0 50% 50% 0"; - - this.element.appendChild(tail); - this.tail = tail; - } - - createTrailParticles() { - for (let i = 0; i < 5; i++) { - this.addTrailParticle(); - } - } - - addTrailParticle() { - const particle = document.createElement("div"); - const size = Math.random() * 2 + 1; - const colors = this.colors; - - particle.style.width = `${size}px`; - particle.style.height = `${size}px`; - particle.style.borderRadius = "50%"; - particle.style.background = colors.mid; - particle.style.position = "absolute"; - particle.style.left = `${this.x}px`; - particle.style.top = `${this.y}px`; - particle.style.boxShadow = `0 0 ${size * 3}px ${colors.glow}`; - particle.style.opacity = "0.7"; - particle.style.zIndex = "1"; - particle.style.pointerEvents = "none"; - - this.container.appendChild(particle); - - this.particles.push({ - element: particle, - life: 1.0, - x: this.x, - y: this.y, - vx: (Math.random() - 0.5) * 0.5, - vy: (Math.random() - 0.5) * 0.5, - size: size, - }); - } - - update() { - this.x += this.dx; - this.y += this.dy; - this.life -= 0.005; - - this.element.style.left = `${this.x}px`; - this.element.style.top = `${this.y}px`; - this.element.style.opacity = this.life; - - // Update tail direction - const tailAngle = Math.atan2(this.dy, this.dx) + Math.PI; - const tails = this.element.querySelectorAll("div:not(.particle)"); - tails.forEach((tail) => { - if (tail !== this.head) { - tail.style.transform = `translate(0, -50%) rotate(${tailAngle}rad)`; - tail.style.opacity = this.life; - } - }); - - if (Math.random() < 0.3) { - this.addTrailParticle(); - } - - // Update existing particles with pixel positioning - for (let i = this.particles.length - 1; i >= 0; i--) { - const p = this.particles[i]; - p.life -= 0.02; - p.x += p.vx; - p.y += p.vy; - - p.element.style.left = `${p.x}px`; - p.element.style.top = `${p.y}px`; - p.element.style.opacity = p.life; - p.element.style.transform = `scale(${p.life})`; - - if (p.life <= 0) { - p.element.remove(); - this.particles.splice(i, 1); - } - } - - if ( - this.x < -50 || - this.x > this.containerRect.width + 50 || - this.y < -50 || - this.y > this.containerRect.height + 50 || - this.life <= 0 - ) { - // Fade out particles - this.particles.forEach((p) => { - p.element.style.transition = "opacity 0.5s"; - p.element.style.opacity = "0"; - setTimeout(() => p.element.remove(), 500); - }); - this.remove(); - return false; - } - return true; - } - - remove() { - if (this.life > 0.3) { - this.createExplosion(); - } - - setTimeout(() => { - this.element.remove(); - }, 300); - } - - createExplosion() { - for (let i = 0; i < 8; i++) { - const particle = document.createElement("div"); - const size = Math.random() * 3 + 2; - const colors = this.colors; - - particle.style.width = `${size}px`; - particle.style.height = `${size}px`; - particle.style.borderRadius = "50%"; - particle.style.background = colors.core; - particle.style.position = "absolute"; - particle.style.left = `${this.x}px`; - particle.style.top = `${this.y}px`; - particle.style.boxShadow = `0 0 ${size * 4}px ${colors.glow}`; - particle.style.opacity = "0.8"; - particle.style.zIndex = "2"; - - this.container.appendChild(particle); - - // Animate explosion - const angle = (i / 8) * Math.PI * 2; - const distance = Math.random() * 20 + 10; - const duration = Math.random() * 500 + 500; - - particle.animate( - [ - { - transform: "translate(0, 0) scale(1)", - opacity: 0.8, - }, - { - transform: `translate(${Math.cos(angle) * distance}px, ${ - Math.sin(angle) * distance - }px) scale(0.1)`, - opacity: 0, - }, - ], - { - duration: duration, - easing: "cubic-bezier(0.4, 0, 0.2, 1)", - } - ).onfinish = () => particle.remove(); - } - } -} - -export default Meteor; diff --git a/src/js/animation/Star.js b/src/js/animation/Star.js deleted file mode 100644 index 53b21f2..0000000 --- a/src/js/animation/Star.js +++ /dev/null @@ -1,63 +0,0 @@ -class Star { - constructor(container) { - this.element = document.createElement("div"); - this.element.classList.add("star"); - this.container = container; - this.speed = Math.random() * 0.5 + 0.1; - - // Random direction angle (0 to 360 degrees) - this.angle = Math.random() * Math.PI * 2; - this.dx = Math.cos(this.angle) * this.speed; - this.dy = Math.sin(this.angle) * this.speed; - - this.x = Math.random() * 100; - this.y = Math.random() * 100; - - this.color = this.getRandomStarColor(); - this.init(); - } - - getRandomStarColor() { - const colors = [ - "rgba(255, 255, 255, 0.9)", // Pure white - "rgba(255, 250, 200, 0.9)", // Warm white - "rgba(200, 220, 255, 0.9)", // Cool blue-white - "rgba(255, 220, 180, 0.9)", // Yellow-white - "rgba(180, 200, 255, 0.9)", // Blue-white - ]; - return colors[Math.floor(Math.random() * colors.length)]; - } - - init() { - const size = Math.random() * 3 + 0.5; - this.element.style.width = `${size}px`; - this.element.style.height = `${size}px`; - this.element.style.left = `${this.x}%`; - this.element.style.top = `${this.y}%`; - this.element.style.background = this.color; - this.element.style.boxShadow = `0 0 ${size * 2}px ${this.color}`; - this.element.style.animationDelay = `${Math.random() * 5}s`; - this.element.style.animationDuration = `${3 + Math.random() * 4}s`; - this.container.appendChild(this.element); - } - - update() { - this.x += this.dx * 0.05; - this.y += this.dy * 0.05; - - // Wrap around when star goes off screen - if (this.y > 100) this.y = 0; - if (this.y < 0) this.y = 100; - if (this.x > 100) this.x = 0; - if (this.x < 0) this.x = 100; - - this.element.style.left = `${this.x}%`; - this.element.style.top = `${this.y}%`; - } - - remove() { - this.element.remove(); - } -} - -export default Star; diff --git a/src/js/animation/starBackground.js b/src/js/animation/starBackground.js deleted file mode 100644 index 42b0d0d..0000000 --- a/src/js/animation/starBackground.js +++ /dev/null @@ -1,81 +0,0 @@ -import Star from "./Star.js"; -import Meteor from "./Meteor.js"; - -const starInstances = []; -const meteorInstances = []; - -function createStars() { - const stars = document.getElementById("stars"); - const count = 400; - stars.innerHTML = ""; - starInstances.length = 0; - - for (let i = 0; i < count; i++) { - const star = new Star(stars); - starInstances.push(star); - } -} - -function injectStarCSS() { - const style = document.createElement("style"); - style.textContent = ` - .star { - position: absolute; - border-radius: 50%; - animation: twinkle ease-in-out infinite; - } - - @keyframes twinkle { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.3; } - } - `; - document.head.appendChild(style); -} - -function trySpawnMeteor() { - const spawnChance = 0.12; - if (Math.random() < spawnChance) { - const stars = document.getElementById("stars"); - const newMeteor = new Meteor(stars); - meteorInstances.push(newMeteor); - } -} - -function animateStars() { - starInstances.forEach((star) => star.update()); - - // Update meteors and remove dead ones - for (let i = meteorInstances.length - 1; i >= 0; i--) { - if (!meteorInstances[i].update()) { - meteorInstances.splice(i, 1); - } - } - - requestAnimationFrame(animateStars); -} - -function createMeteorBurst() { - for (let i = 0; i < 3; i++) { - setTimeout(() => { - const stars = document.getElementById("stars"); - const newMeteor = new Meteor(stars); - meteorInstances.push(newMeteor); - }, i * 200); - } -} - -function init() { - injectStarCSS(); - createStars(); - animateStars(); - - setInterval(trySpawnMeteor, 2000); - setInterval(createMeteorBurst, 15000); -} - -if (document.readyState === "loading") { - document.addEventListener("DOMContentLoaded", init); -} else { - init(); -} diff --git a/src/js/form.js b/src/js/form.js deleted file mode 100644 index 4dbfa2e..0000000 --- a/src/js/form.js +++ /dev/null @@ -1,22 +0,0 @@ -// 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."); - } - }); - } -} diff --git a/src/js/main.js b/src/js/main.js deleted file mode 100644 index bd2f14a..0000000 --- a/src/js/main.js +++ /dev/null @@ -1,27 +0,0 @@ -// 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", - }); - } - }); - }); -}); diff --git a/src/js/navigation.js b/src/js/navigation.js deleted file mode 100644 index 974476d..0000000 --- a/src/js/navigation.js +++ /dev/null @@ -1,106 +0,0 @@ -// Navigation JavaScript -let lastScrollY = window.scrollY; -let ticking = false; - -function updateNavigation() { - const navigation = document.getElementById("navigation"); - const scrolled = window.scrollY > 50; - - if (scrolled) { - navigation.classList.add("scrolled"); - - // Hide/show nav on scroll - if (window.scrollY > lastScrollY && window.scrollY > 100) { - navigation.classList.add("hidden"); - } else { - navigation.classList.remove("hidden"); - } - } else { - navigation.classList.remove("scrolled", "hidden"); - } - - lastScrollY = window.scrollY; - ticking = false; -} - -function requestTick() { - if (!ticking) { - requestAnimationFrame(updateNavigation); - ticking = true; - } -} - -// Mobile navigation functionality -function setupMobileNavigation() { - const burgerMenu = document.getElementById("burger-menu"); - const mainNav = document.getElementById("main-nav"); - const body = document.body; - - // Create overlay for mobile menu - const overlay = document.createElement("div"); - overlay.className = "nav-overlay"; - document.body.appendChild(overlay); - - if (burgerMenu && mainNav) { - burgerMenu.addEventListener("click", function () { - const isActive = mainNav.classList.contains("active"); - - if (isActive) { - // Close menu - mainNav.classList.remove("active"); - burgerMenu.classList.remove("active"); - overlay.classList.remove("active"); - body.classList.remove("nav-open"); - } else { - // Open menu - mainNav.classList.add("active"); - burgerMenu.classList.add("active"); - overlay.classList.add("active"); - body.classList.add("nav-open"); - } - }); - - // Close menu when clicking on overlay - overlay.addEventListener("click", function () { - mainNav.classList.remove("active"); - burgerMenu.classList.remove("active"); - overlay.classList.remove("active"); - body.classList.remove("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"); - overlay.classList.remove("active"); - body.classList.remove("nav-open"); - - // Update active state - navLinks.forEach((l) => l.classList.remove("active")); - this.classList.add("active"); - }); - }); - - // Set initial active state based on current hash - function setActiveNavLink() { - const currentHash = window.location.hash || "#home"; - navLinks.forEach((link) => { - if (link.getAttribute("href") === currentHash) { - link.classList.add("active"); - } else { - link.classList.remove("active"); - } - }); - } - - // Update active state on hash change - window.addEventListener("hashchange", setActiveNavLink); - setActiveNavLink(); - } -} - -// Initialize navigation -window.addEventListener("scroll", requestTick); -window.addEventListener("load", updateNavigation); diff --git a/src/js/overview.js b/src/js/overview.js deleted file mode 100644 index 9dd7bf2..0000000 --- a/src/js/overview.js +++ /dev/null @@ -1,57 +0,0 @@ -// 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 -}); diff --git a/src/js/portfolioCard.js b/src/js/portfolioCard.js deleted file mode 100644 index 2fd2d79..0000000 --- a/src/js/portfolioCard.js +++ /dev/null @@ -1,228 +0,0 @@ -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 = ` - - - - - - - -
-
- -
-
-

- ${title} -

-

${desc}

- ${ - collaboration - ? ` -
- ${collaboration} -
- ` - : "" - } -
- ${tags - .map((tag) => `${tag.trim()}`) - .join("")} -
-
- -
- `; - } -} - -customElements.define("portfolio-card", PortfolioCard); diff --git a/src/js/portfolioFilter.js b/src/js/portfolioFilter.js deleted file mode 100644 index 7779c87..0000000 --- a/src/js/portfolioFilter.js +++ /dev/null @@ -1,95 +0,0 @@ -// 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 = ` - -

No projects found

-

Try adjusting your search or filter criteria

- `; - - // 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(); -}); diff --git a/src/js/sectionTracker.js b/src/js/sectionTracker.js deleted file mode 100644 index e392724..0000000 --- a/src/js/sectionTracker.js +++ /dev/null @@ -1,111 +0,0 @@ -// Section tracking and navigation highlighting -document.addEventListener("DOMContentLoaded", function () { - const sections = document.querySelectorAll("section[id]"); - const navLinks = document.querySelectorAll(".nav-links a"); - - // Configuration - const offset = 100; // Offset for when section becomes "active" (accounts for fixed nav) - let isScrolling = false; - - function getCurrentSection() { - let currentSection = ""; - const scrollPosition = window.scrollY + offset; - - // Find which section we're currently in - sections.forEach((section) => { - const sectionTop = section.offsetTop; - const sectionHeight = section.offsetHeight; - const sectionId = section.getAttribute("id"); - - if ( - scrollPosition >= sectionTop && - scrollPosition < sectionTop + sectionHeight - ) { - currentSection = sectionId; - } - }); - - // Special case: if we're at the very top, activate the first section - if (window.scrollY < 100) { - currentSection = sections[0]?.getAttribute("id") || ""; - } - - return currentSection; - } - - function updateActiveNavLink() { - const currentSection = getCurrentSection(); - - navLinks.forEach((link) => { - const href = link.getAttribute("href"); - - // Remove active class from all links - link.classList.remove("active"); - - // Add active class to matching link - if (href === `#${currentSection}`) { - link.classList.add("active"); - } - }); - } - - // Throttle scroll events for better performance - function handleScroll() { - if (!isScrolling) { - window.requestAnimationFrame(() => { - updateActiveNavLink(); - isScrolling = false; - }); - isScrolling = true; - } - } - - // Listen for scroll events - window.addEventListener("scroll", handleScroll); - - // Update on page load - updateActiveNavLink(); - - // Also update when clicking nav links (for smooth scroll) - navLinks.forEach((link) => { - link.addEventListener("click", function (e) { - // Remove active from all - navLinks.forEach((l) => l.classList.remove("active")); - // Add active to clicked link - this.classList.add("active"); - - // Let the scroll handler update it properly after scroll completes - setTimeout(updateActiveNavLink, 100); - }); - }); - - // Handle hash changes (browser back/forward) - window.addEventListener("hashchange", function () { - setTimeout(updateActiveNavLink, 100); - }); - - // Intersection Observer for more precise tracking (progressive enhancement) - if ("IntersectionObserver" in window) { - const observerOptions = { - rootMargin: "-20% 0px -70% 0px", // Trigger when section is roughly in the middle of viewport - threshold: 0, - }; - - const observer = new IntersectionObserver((entries) => { - entries.forEach((entry) => { - if (entry.isIntersecting) { - const sectionId = entry.target.getAttribute("id"); - navLinks.forEach((link) => { - link.classList.remove("active"); - if (link.getAttribute("href") === `#${sectionId}`) { - link.classList.add("active"); - } - }); - } - }); - }, observerOptions); - - // Observe all sections - sections.forEach((section) => observer.observe(section)); - } -}); diff --git a/src/styles/styles.css b/src/styles/styles.css deleted file mode 100644 index 3229eb9..0000000 --- a/src/styles/styles.css +++ /dev/null @@ -1,1943 +0,0 @@ -/* 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); - --accent-gradient-reverse: linear-gradient(135deg, #7c3aed, #00f5ff); - - --purple: #8b5cf6; - --purple-light: #a78bfa; - --purple-dark: #7c3aed; - --purple-muted: #6d28d9; - --shadow-purple: rgba(139, 92, 246, 0.3); - - --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; -} - -body.nav-open { - overflow: hidden; -} - -/* 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; -} - -/* Enhanced Background Effects */ -.animated-bg { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - z-index: -2; - background: radial-gradient( - circle at 20% 50%, - rgba(124, 58, 237, 0.15) 0%, - transparent 50% - ), - radial-gradient( - circle at 80% 20%, - rgba(0, 245, 255, 0.12) 0%, - transparent 50% - ), - radial-gradient( - circle at 40% 80%, - rgba(124, 58, 237, 0.1) 0%, - transparent 50% - ); - animation: gradientShift 15s ease infinite; -} - -@keyframes gradientShift { - 0%, - 100% { - background-position: 0% 50%, 100% 50%, 50% 100%; - } - 50% { - background-position: 100% 50%, 0% 50%, 50% 0%; - } -} - -.stars { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - pointer-events: none; - z-index: -1; -} - -.star { - position: absolute; - 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); - } -} - -/* Enhanced Navigation with Fixed Background Animations */ -nav { - position: fixed; - top: 0; - width: 100%; - background: rgba(10, 10, 10, 0.95); - backdrop-filter: blur(20px) saturate(180%); - border-bottom: 1px solid rgba(255, 255, 255, 0.08); - z-index: var(--z-navigation); - transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); - transform: translateY(0); -} - -/* Hide nav on scroll down, show on scroll up */ -nav.hidden { - transform: translateY(-100%); -} - -nav.scrolled { - background: rgba(10, 10, 10, 0.98); - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); - border-bottom-color: rgba(124, 58, 237, 0.2); -} - -.nav-container { - max-width: 1400px; - margin: 0 auto; - padding: 0 var(--spacing-lg); - display: flex; - align-items: center; - justify-content: space-between; - height: 70px; -} - -.logo { - font-weight: 800; - font-size: 1.5rem; - background: var(--accent-gradient); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - position: relative; - padding: var(--spacing-xs) 0; -} - -.logo::after { - content: ""; - position: absolute; - bottom: 0; - left: 0; - width: 0; - height: 2px; - background: var(--accent-gradient); - transition: width 0.3s ease; -} - -.logo:hover::after { - width: 100%; -} - -.nav-links { - display: flex; - gap: var(--spacing-md); - align-items: center; -} - -.nav-links a { - color: var(--text-secondary); - font-weight: 500; - font-size: 0.9rem; - padding: var(--spacing-sm) var(--spacing-md); - border-radius: var(--radius-md); - transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); - position: relative; - overflow: hidden; -} - -/* Fixed background animation - only shows on hover */ -.nav-links a::before { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: var(--accent-gradient); - opacity: 0; - transition: opacity 0.3s ease; - z-index: -1; - border-radius: var(--radius-md); -} - -.nav-links a:hover::before { - opacity: 0.1; -} - -/* Underline animation */ -.nav-links a::after { - content: ""; - position: absolute; - bottom: 0; - left: 50%; - transform: translateX(-50%); - width: 0; - height: 2px; - background: var(--accent-primary); - transition: width 0.3s ease; - border-radius: 2px; -} - -.nav-links a:hover { - color: var(--accent-primary); - transform: translateY(-1px); -} - -.nav-links a:hover::after { - width: 80%; -} - -/* Active state */ -.nav-links a.active { - color: var(--accent-primary); - background: rgba(0, 245, 255, 0.1); -} - -.nav-links a.active::after { - width: 80%; -} - -.nav-links a.active::before { - opacity: 0.1; -} - -/* Mobile menu button */ -.mobile-menu-btn { - display: none; - background: none; - border: none; - color: var(--text-primary); - font-size: 1.5rem; - cursor: pointer; - padding: var(--spacing-sm); - border-radius: var(--radius-md); - transition: all 0.3s ease; - position: relative; - z-index: 1001; -} - -.mobile-menu-btn:hover { - background: rgba(124, 58, 237, 0.1); - color: var(--accent-primary); -} - -.mobile-menu-btn.active { - color: var(--accent-primary); -} - -/* Mobile menu styles */ -@media (max-width: 768px) { - .mobile-menu-btn { - display: block; - } - - .nav-links { - position: fixed; - top: 0; - right: -100%; - width: 280px; - height: 100vh; - background: rgba(10, 10, 10, 0.98); - backdrop-filter: blur(30px); - flex-direction: column; - padding: 80px var(--spacing-lg) var(--spacing-lg); - transition: right 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); - border-left: 1px solid rgba(255, 255, 255, 0.1); - box-shadow: -10px 0 30px rgba(0, 0, 0, 0.3); - } - - .nav-links.active { - right: 0; - } - - .nav-links a { - width: 100%; - text-align: center; - padding: var(--spacing-md); - font-size: 1.1rem; - border-radius: var(--radius-lg); - margin-bottom: var(--spacing-xs); - } - - .nav-links a::after { - display: none; - } - - .nav-links a::before { - border-radius: var(--radius-lg); - } - - /* Overlay for mobile menu */ - .nav-overlay { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.5); - backdrop-filter: blur(5px); - z-index: 999; - opacity: 0; - visibility: hidden; - transition: all 0.3s ease; - } - - .nav-overlay.active { - opacity: 1; - visibility: visible; - } -} - -/* Enhanced scroll behavior */ -.nav-scroll-hide { - animation: navHide 0.4s ease forwards; -} - -.nav-scroll-show { - animation: navShow 0.4s ease forwards; -} - -@keyframes navHide { - from { - transform: translateY(0); - } - to { - transform: translateY(-100%); - } -} - -@keyframes navShow { - from { - transform: translateY(-100%); - } - to { - transform: translateY(0); - } -} - -/* Container */ -.container { - max-width: 1400px; - margin: 0 auto; - padding: 0 var(--spacing-lg); -} - -/* Enhanced Hero Section */ -.hero { - min-height: 100vh; - display: flex; - align-items: center; - padding-top: 80px; - position: relative; - overflow: hidden; -} - -.hero::before { - content: ""; - position: absolute; - top: 50%; - left: 50%; - width: 100%; - height: 100%; - background: radial-gradient( - circle at center, - rgba(124, 58, 237, 0.1) 0%, - transparent 70% - ); - transform: translate(-50%, -50%); - animation: pulse 4s ease-in-out infinite; -} - -@keyframes pulse { - 0%, - 100% { - opacity: 0.5; - transform: translate(-50%, -50%) scale(1); - } - 50% { - opacity: 0.8; - transform: translate(-50%, -50%) scale(1.1); - } -} - -.hero-content { - max-width: 800px; - margin: 0 auto; - text-align: center; - padding: var(--spacing-lg) 0; - position: relative; - z-index: 1; -} - -.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; - animation: slideUp 1s ease-out; -} - -@keyframes slideUp { - from { - opacity: 0; - transform: translateY(30px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -.hero h1 .highlight { - background: var(--accent-gradient); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - position: relative; - display: inline-block; -} - -.hero h1 .highlight::after { - content: ""; - position: absolute; - bottom: -5px; - left: 0; - width: 100%; - height: 3px; - background: var(--accent-gradient); - transform: scaleX(0); - transform-origin: left; - animation: expandLine 1s ease-out 0.5s forwards; -} - -@keyframes expandLine { - to { - transform: scaleX(1); - } -} - -.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; - animation: slideUp 1s ease-out 0.2s both; -} - -.hero-buttons { - display: flex; - gap: var(--spacing-sm); - justify-content: center; - flex-wrap: wrap; - animation: slideUp 1s ease-out 0.4s both; -} - -/* Enhanced 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::before { - content: ""; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient( - 90deg, - transparent, - rgba(255, 255, 255, 0.2), - transparent - ); - transition: left 0.5s ease; -} - -.btn:hover::before { - left: 100%; -} - -.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(-3px); - box-shadow: 0 15px 30px rgba(0, 245, 255, 0.4); -} - -.btn-secondary { - background: transparent; - color: var(--text-primary); - border: 2px solid var(--border-accent); - position: relative; - overflow: hidden; -} - -.btn-secondary::after { - content: ""; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: var(--accent-gradient); - opacity: 0.1; - transition: left 0.3s ease; - z-index: -1; -} - -.btn-secondary:hover:not(:disabled) { - background: var(--bg-card); - border-color: var(--accent-primary); - transform: translateY(-3px); -} - -.btn-secondary:hover::after { - left: 0; -} - -/* Enhanced Sections */ -.section { - padding: 8rem 0; - position: relative; -} - -.section::before { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: linear-gradient( - 180deg, - transparent 0%, - rgba(124, 58, 237, 0.03) 50%, - transparent 100% - ); - pointer-events: none; -} - -.section-header { - text-align: center; - margin-bottom: var(--spacing-2xl); - position: relative; -} - -.section-title { - font-size: clamp(2rem, 4vw, 3rem); - font-weight: 700; - margin-bottom: var(--spacing-sm); - letter-spacing: -0.02em; - position: relative; - display: inline-block; -} - -.section-title::after { - content: ""; - position: absolute; - bottom: -10px; - left: 50%; - transform: translateX(-50%); - width: 60px; - height: 3px; - background: var(--accent-gradient); - border-radius: 2px; -} - -.section-subtitle { - font-size: 1.125rem; - color: var(--text-secondary); - max-width: 600px; - margin: 0 auto; - line-height: 1.6; -} - -/* Enhanced Portfolio Controls */ -.portfolio-controls { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: var(--spacing-xl); - flex-wrap: wrap; - gap: var(--spacing-md); -} - -.filter-buttons { - display: flex; - gap: var(--spacing-sm); - flex-wrap: wrap; -} - -.filter-btn { - padding: 0.75rem 1.5rem; - background: var(--bg-card); - border: 1px solid var(--border-subtle); - border-radius: var(--radius-md); - color: var(--text-secondary); - font-weight: 500; - cursor: pointer; - transition: all 0.3s ease; - position: relative; - overflow: hidden; -} - -.filter-btn::before { - content: ""; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: var(--accent-gradient); - transition: left 0.3s ease; - z-index: -1; -} - -.filter-btn:hover { - background: var(--bg-card-hover); - color: var(--text-primary); - transform: translateY(-2px); - border-color: var(--accent-primary); -} - -.filter-btn.active { - background: var(--accent-gradient); - color: var(--bg-primary); - border-color: transparent; - box-shadow: var(--shadow-glow); -} - -.search-box { - position: relative; - max-width: 300px; - width: 100%; -} - -.search-box input { - width: 100%; - padding: 0.75rem 1rem 0.75rem 2.5rem; - background: var(--bg-card); - border: 1px solid var(--border-subtle); - border-radius: var(--radius-md); - color: var(--text-primary); - font-size: 0.95rem; - transition: all 0.3s ease; -} - -.search-box input:focus { - outline: none; - border-color: var(--accent-primary); - box-shadow: 0 0 0 3px rgba(0, 245, 255, 0.1); - background: var(--bg-card-hover); -} - -.search-box i { - position: absolute; - left: 1rem; - top: 50%; - transform: translateY(-50%); - color: var(--text-muted); - transition: color 0.3s ease; -} - -.search-box input:focus + i { - color: var(--accent-primary); -} - -/* Enhanced Portfolio Grid */ -.portfolio-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(350px, 1fr)); - gap: var(--spacing-lg); -} - -portfolio-card { - background: var(--bg-card); - border: 1px solid var(--border-subtle); - border-radius: var(--radius-lg); - overflow: hidden; - transition: all 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); - position: relative; - display: block; - opacity: 0; - transform: translateY(30px); - animation: fadeInUp 0.6s ease forwards; -} - -@keyframes fadeInUp { - to { - opacity: 1; - transform: translateY(0); - } -} - -portfolio-card::before { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 3px; - background: var(--accent-gradient); - transform: scaleX(0); - transform-origin: left; - transition: transform 0.3s ease; -} - -portfolio-card:hover::before { - transform: scaleX(1); -} - -portfolio-card:hover { - transform: translateY(-10px) scale(1.02); - background: var(--bg-card-hover); - box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3), 0 0 30px rgba(0, 245, 255, 0.1); - border-color: var(--border-accent); -} - -.portfolio-img { - display: flex; - align-items: center; - justify-content: center; - height: 120px; - background: var(--accent-gradient); - font-size: 2.5rem; - color: #ffffff; - position: relative; - overflow: hidden; -} - -.portfolio-img::after { - content: ""; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient( - 90deg, - transparent, - rgba(255, 255, 255, 0.2), - transparent - ); - transition: left 0.5s ease; -} - -portfolio-card:hover .portfolio-img::after { - left: 100%; -} - -.portfolio-content { - padding: var(--spacing-lg); -} - -.portfolio-title { - display: flex; - align-items: center; - gap: var(--spacing-sm); - font-size: 1.5rem; - font-weight: 600; - margin-bottom: var(--spacing-sm); - color: var(--text-primary); -} - -.portfolio-desc { - color: var(--text-secondary); - margin-bottom: var(--spacing-md); - line-height: 1.6; -} - -.portfolio-tags { - display: flex; - flex-wrap: wrap; - gap: var(--spacing-xs); - margin-bottom: var(--spacing-md); -} - -.tag { - padding: 0.25rem 0.75rem; - 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); - transition: all 0.3s ease; -} - -.tag:hover { - background: rgba(0, 245, 255, 0.2); - transform: translateY(-1px); -} - -/* Enhanced Portfolio Button */ -.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; -} - -/* Enhanced Collaboration Badge */ -.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; - position: relative; - overflow: hidden; -} - -.collaboration-badge::before { - content: ""; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: linear-gradient( - 90deg, - transparent, - rgba(255, 255, 255, 0.3), - transparent - ); - transition: left 0.5s ease; -} - -.collaboration-badge:hover::before { - left: 100%; -} - -@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 Stats Section */ -.stats-section { - background: var(--bg-secondary); - padding: var(--spacing-2xl) 0; - position: relative; - overflow: hidden; -} - -.stats-section::before { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: linear-gradient( - 45deg, - transparent 30%, - rgba(124, 58, 237, 0.05) 50%, - transparent 70% - ); - animation: shimmer 3s ease-in-out infinite; -} - -@keyframes shimmer { - 0%, - 100% { - transform: translateX(-100%); - } - 50% { - transform: translateX(100%); - } -} - -.stats-container { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); - gap: var(--spacing-lg); - text-align: center; - position: relative; - z-index: 1; -} - -.stat-item { - padding: var(--spacing-lg); - position: relative; -} - -.stat-item::before { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: var(--accent-gradient); - opacity: 0; - border-radius: var(--radius-lg); - transition: opacity 0.3s ease; - z-index: -1; -} - -.stat-item:hover::before { - opacity: 0.05; -} - -.stat-number { - font-size: 3rem; - font-weight: 800; - background: var(--accent-gradient); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - margin-bottom: var(--spacing-sm); -} - -.stat-label { - color: var(--text-secondary); - font-weight: 500; - font-size: 1.1rem; -} - -/* Enhanced Team Section */ -.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.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); - position: relative; - overflow: hidden; -} - -.team-member::before { - content: ""; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: var(--accent-gradient); - opacity: 0.05; - transition: left 0.3s ease; - z-index: -1; -} - -.team-member:hover::before { - left: 0; -} - -.team-member:hover { - transform: translateY(-8px) scale(1.02); - 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: #ffffff; - margin: 0 auto var(--spacing-md); - position: relative; - transition: all 0.3s ease; -} - -.team-member:hover .member-avatar { - transform: scale(1.1) rotate(5deg); -} - -.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; -} - -/* Enhanced 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; - position: relative; - padding-left: var(--spacing-lg); -} - -.about-content p::before { - content: ""; - position: absolute; - left: 0; - top: 0; - height: 100%; - width: 3px; - background: var(--accent-gradient); - border-radius: 2px; - transform: scaleY(0); - transition: transform 0.3s ease; -} - -.about-content p:hover::before { - transform: scaleY(1); -} - -.about-content p:last-child { - margin-bottom: 0; -} - -/* Enhanced 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.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); - position: relative; - overflow: hidden; -} - -.principle-card::before { - content: ""; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: var(--accent-gradient); - opacity: 0.05; - transition: left 0.3s ease; - z-index: -1; -} - -.principle-card:hover::before { - left: 0; -} - -.principle-card:hover { - transform: translateY(-8px) scale(1.02); - 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: #ffffff; - transition: all 0.3s ease; -} - -.principle-card:hover .principle-icon { - transform: scale(1.1) rotate(10deg); -} - -.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; -} - -/* Enhanced 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); - transition: all 0.3s ease; - padding: var(--spacing-md); - border-radius: var(--radius-lg); -} - -.contact-item:hover { - background: var(--bg-card); - transform: translateX(10px); -} - -.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: #ffffff; - flex-shrink: 0; - transition: all 0.3s ease; -} - -.contact-item:hover .contact-icon { - transform: scale(1.1) rotate(5deg); -} - -.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; - position: relative; -} - -.contact-details a::after { - content: ""; - position: absolute; - bottom: -2px; - left: 0; - width: 0; - height: 1px; - background: var(--accent-primary); - transition: width 0.3s ease; -} - -.contact-details a:hover { - color: var(--accent-primary); -} - -.contact-details a:hover::after { - width: 100%; -} - -/* Enhanced Contact Form */ -.contact-form { - background: var(--bg-card); - border: 1px solid var(--border-subtle); - border-radius: var(--radius-lg); - padding: var(--spacing-xl); - transition: all 0.3s ease; -} - -.contact-form:hover { - border-color: var(--accent-primary); - box-shadow: var(--shadow-glow); -} - -.form-group { - margin-bottom: var(--spacing-md); - position: relative; -} - -.form-group label { - display: block; - margin-bottom: var(--spacing-xs); - font-weight: 500; - color: var(--text-primary); - font-size: 0.9rem; - transition: color 0.3s ease; -} - -.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); - background: var(--bg-card-hover); -} - -.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); -} - -/* Enhanced Footer */ -.footer { - background: var(--bg-secondary); - border-top: 1px solid var(--border-subtle); - padding: var(--spacing-2xl) 0 var(--spacing-lg); - position: relative; -} - -.footer::before { - content: ""; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 1px; - background: var(--accent-gradient); -} - -.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; - position: relative; - overflow: hidden; -} - -.social-link::before { - content: ""; - position: absolute; - top: 0; - left: -100%; - width: 100%; - height: 100%; - background: var(--accent-gradient); - transition: left 0.3s ease; - z-index: -1; -} - -.social-link:hover::before { - left: 0; -} - -.social-link:hover { - background: var(--accent-gradient); - color: #ffffff; - transform: translateY(-3px) scale(1.1); - border-color: transparent; -} - -.footer-links h4 { - font-size: 1.1rem; - font-weight: 600; - color: var(--text-primary); - margin-bottom: var(--spacing-sm); - position: relative; -} - -.footer-links h4::after { - content: ""; - position: absolute; - bottom: -5px; - left: 0; - width: 30px; - height: 2px; - background: var(--accent-primary); -} - -.footer-links ul { - display: flex; - flex-direction: column; - gap: var(--spacing-xs); -} - -.footer-links a { - color: var(--text-secondary); - font-size: 0.9rem; - transition: all 0.3s ease; - padding: 0.25rem 0; - position: relative; -} - -.footer-links a::before { - content: ""; - position: absolute; - bottom: 0; - left: 0; - width: 0; - height: 1px; - background: var(--accent-primary); - transition: width 0.3s ease; -} - -.footer-links a:hover { - color: var(--accent-primary); - transform: translateX(5px); -} - -.footer-links a:hover::before { - width: 100%; -} - -.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); - transition: all 0.3s ease; -} - -.badge:hover { - background: var(--accent-gradient); - color: var(--bg-primary); - border-color: transparent; - transform: translateY(-2px); -} - -.badge i { - color: var(--accent-primary); -} - -.badge:hover i { - color: var(--bg-primary); -} - -/* Enhanced No Results */ -.no-results { - grid-column: 1 / -1; - text-align: center; - padding: var(--spacing-2xl); - color: var(--text-muted); - position: relative; -} - -.no-results i { - font-size: 3rem; - margin-bottom: var(--spacing-md); - opacity: 0.5; - animation: bounce 2s infinite; -} - -@keyframes bounce { - 0%, - 20%, - 50%, - 80%, - 100% { - transform: translateY(0); - } - 40% { - transform: translateY(-10px); - } - 60% { - transform: translateY(-5px); - } -} - -.no-results h3 { - font-size: 1.5rem; - margin-bottom: var(--spacing-sm); - color: var(--text-secondary); -} - -.no-results p { - color: var(--text-muted); -} - -/* 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 { - position: fixed; - top: 0; - right: -100%; - width: 280px; - height: 100vh; - background: rgba(10, 10, 10, 0.98); - backdrop-filter: blur(30px); - flex-direction: column; - padding: 80px var(--spacing-lg) var(--spacing-lg); - transition: right 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94); - border-left: 1px solid rgba(255, 255, 255, 0.1); - box-shadow: -10px 0 30px rgba(0, 0, 0, 0.3); - } - - .nav-links.active { - right: 0; - } - - .nav-links a { - width: 100%; - text-align: center; - padding: var(--spacing-md); - font-size: 1.1rem; - border-radius: var(--radius-lg); - margin-bottom: var(--spacing-xs); - } - - .nav-links a::after { - display: none; - } - - .nav-links a::before { - border-radius: var(--radius-lg); - } - - .nav-overlay { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.5); - backdrop-filter: blur(5px); - z-index: 999; - opacity: 0; - visibility: hidden; - transition: all 0.3s ease; - } - - .nav-overlay.active { - opacity: 1; - visibility: visible; - } - - .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; - } - - .portfolio-controls { - flex-direction: column; - align-items: stretch; - } - - .filter-buttons { - justify-content: center; - } - - .portfolio-grid { - grid-template-columns: 1fr; - } - - .team-grid { - grid-template-columns: 1fr; - } - - .principles-grid { - grid-template-columns: 1fr; - } - - .stats-container { - grid-template-columns: repeat(2, 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); - } - - .portfolio-btn { - padding: 0.9rem 1.5rem; - font-size: 0.85rem; - } -} - -@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); - } - - .stats-container { - grid-template-columns: 1fr; - } -} - -/* 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; - } -} diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..d14c826 --- /dev/null +++ b/styles.css @@ -0,0 +1,432 @@ +/* + 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 . +*/ + +: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 tag covers the entire card */ +section .card a { + display: flex; /* Use flex to make 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; + } +} diff --git a/webGames/index.html b/webGames/index.html new file mode 100644 index 0000000..7f1a0bf --- /dev/null +++ b/webGames/index.html @@ -0,0 +1,110 @@ + + + + + + Game Collection + + + + + + + +
+

Game Collection

+
+ +
+ +
+ + + + diff --git a/webGames/styles.css b/webGames/styles.css new file mode 100644 index 0000000..e9a6fcf --- /dev/null +++ b/webGames/styles.css @@ -0,0 +1,120 @@ +/* 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); + } +}