diff --git a/.eleventy.js b/.eleventy.js index b9d0e32b..4f76cc14 100644 --- a/.eleventy.js +++ b/.eleventy.js @@ -1,6 +1,6 @@ const yaml = require("js-yaml"); -module.exports = function(eleventyConfig) { +module.exports = function (eleventyConfig) { // Add this line to copy your external assets eleventyConfig.addPassthroughCopy("src/assets"); // 1. Recognize YAML as a template format @@ -20,11 +20,11 @@ module.exports = function(eleventyConfig) { const fs = require("fs/promises"); const content = await fs.readFile(inputPath, "utf-8"); return yaml.load(content); - } + }, }); // 2. The Randomized Collection - eleventyConfig.addCollection("randomPeople", function(collectionApi) { + eleventyConfig.addCollection("randomPeople", function (collectionApi) { // Grab all yaml files from the users folder const people = collectionApi.getFilteredByGlob("src/users/*.yaml"); @@ -44,7 +44,7 @@ module.exports = function(eleventyConfig) { dir: { input: "src", output: "_site", - includes: "_includes" - } + includes: "_includes", + }, }; }; diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8fcccf1c..fc6f05b7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -8,8 +8,8 @@ on: jobs: deployment: permissions: - pages: write # to deploy to Pages - id-token: write # to verify the deployment originates from an appropriate source + pages: write # to deploy to Pages + id-token: write # to verify the deployment originates from an appropriate source runs-on: ubuntu-latest steps: - name: Checkout code @@ -25,7 +25,7 @@ jobs: - name: Upload artifact uses: actions/upload-pages-artifact@v4 with: - path: '_site' # The directory that contains the deployable files + path: "_site" # The directory that contains the deployable files - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 diff --git a/.markdownlint.yaml b/.markdownlint.yaml new file mode 100644 index 00000000..f1d751b6 --- /dev/null +++ b/.markdownlint.yaml @@ -0,0 +1,5 @@ +# Markdownlint configuration +# Disable line length rule for long URLs and badges +MD013: false +# Allow emphasis for styled section labels +MD036: false diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..5869dfee --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,49 @@ +# Pre-commit configuration for NextCommunity.github.io +# See https://pre-commit.com for more information + +repos: + # Standard pre-commit hooks for basic file checks + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: trailing-whitespace + exclude: ^package-lock\.json$ + - id: end-of-file-fixer + exclude: ^package-lock\.json$ + - id: check-yaml + args: ["--unsafe"] + - id: check-added-large-files + args: ["--maxkb=1000"] + - id: check-json + exclude: ^package-lock\.json$ + - id: check-merge-conflict + - id: check-case-conflict + - id: mixed-line-ending + args: ["--fix=lf"] + + # Prettier for code formatting (JavaScript, CSS, HTML, Markdown, YAML, JSON) + - repo: https://github.com/pre-commit/mirrors-prettier + rev: v3.1.0 + hooks: + - id: prettier + types_or: [javascript, css, html, markdown, yaml, json] + exclude: ^(package-lock\.json|_site/) + additional_dependencies: + - prettier@3.1.0 + + # Markdownlint for markdown files + - repo: https://github.com/igorshubovych/markdownlint-cli + rev: v0.39.0 + hooks: + - id: markdownlint + args: ["--fix"] + exclude: ^node_modules/ + +# Exclude patterns applied to all hooks +exclude: | + (?x)( + ^_site/| + ^node_modules/| + ^\.git/| + package-lock\.json + ) diff --git a/README.md b/README.md index 08aede06..c7dad3eb 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ NextCommunity is a static site directory built with [Eleventy (11ty)](https://www.11ty.dev/) that celebrates the global developer community. Each developer gets their own profile page showcasing their skills, bio, and social links. ### ๐ ๏ธ Tech Stack + - **Static Site Generator**: Eleventy (11ty) - **Templating**: Nunjucks - **Styling**: TailwindCSS @@ -33,6 +34,7 @@ NextCommunity is a static site directory built with [Eleventy (11ty)](https://ww - **Deployment**: GitHub Pages ### โจ Features + - ๐ฒ Randomized display of developer profiles - ๐ Dark/Light theme support - ๐ฑ Fully responsive design @@ -86,7 +88,7 @@ bio: | Write your professional bio here. You can use multiple lines. Share your experience, interests, and what you're passionate about. - + Add your skills, projects, or anything else you'd like to highlight! ``` @@ -123,11 +125,13 @@ git push origin main 2. Click the **"Contribute"** button, then **"Open Pull Request"** 3. Write a clear title: `Add [Your Name] to directory` 4. In the description, mention: - ``` + + ```markdown Fixes #213 - + Adding my profile to the NextCommunity developer directory. ``` + 5. Click **"Create Pull Request"** ### Step 8: Wait for Review โณ @@ -143,25 +147,25 @@ git push origin main ### Required Fields -| Field | Description | Example | -|-------|-------------|---------| -| `name` | Your full name | `John Bampton` | -| `github` | Your GitHub username (without @) | `jbampton` | -| `country` | Your country | `Australia` | -| `location` | Your city | `Brisbane` | -| `role` | Your professional title | `Frontend Developer` | +| Field | Description | Example | +| ----------- | ------------------------------------ | -------------------------- | +| `name` | Your full name | `John Bampton` | +| `github` | Your GitHub username (without @) | `jbampton` | +| `country` | Your country | `Australia` | +| `location` | Your city | `Brisbane` | +| `role` | Your professional title | `Frontend Developer` | | `languages` | Space-separated list of technologies | `JavaScript React Node.js` | -| `bio` | Multi-line biography | See template above | +| `bio` | Multi-line biography | See template above | ### Optional Fields -| Field | Description | Example | -|-------|-------------|---------| -| `website` | Your personal website URL | `https://yoursite.com` | -| `email` | Your email address | `you@example.com` | -| `instagram` | Full Instagram profile URL | `https://instagram.com/username` | -| `twitter` | Full Twitter/X profile URL | `https://twitter.com/username` | -| `linkedin` | Full LinkedIn profile URL | `https://linkedin.com/in/username` | +| Field | Description | Example | +| ----------- | -------------------------- | ---------------------------------- | +| `website` | Your personal website URL | `https://yoursite.com` | +| `email` | Your email address | `you@example.com` | +| `instagram` | Full Instagram profile URL | `https://instagram.com/username` | +| `twitter` | Full Twitter/X profile URL | `https://twitter.com/username` | +| `linkedin` | Full LinkedIn profile URL | `https://linkedin.com/in/username` | ### Field Guidelines @@ -174,6 +178,7 @@ git push origin main ### ๐ Real Examples **Example 1: Minimal Profile** + ```yaml name: Jane Smith github: janesmith @@ -187,6 +192,7 @@ bio: | ``` **Example 2: Complete Profile** + ```yaml name: Carlos Rodriguez github: carlosr @@ -200,7 +206,7 @@ role: Full Stack Engineer languages: TypeScript React Node.js AWS bio: | Full-stack engineer specializing in modern web technologies. - + Currently building cloud-native applications and contributing to open source. Passionate about clean code, testing, and developer experience. ``` @@ -245,7 +251,7 @@ npm run build ### Project Structure -``` +```text NextCommunity.github.io/ โโโ src/ โ โโโ _data/ # Site-wide data files @@ -281,12 +287,14 @@ We're committed to providing a welcoming and inclusive environment. Please be re ### What Gets Approved? โ **Yes:** + - Complete, valid YAML files - Professional bios and appropriate content - Real GitHub profiles - Accurate information โ **No:** + - Spam or promotional content - Offensive or inappropriate material - Fake or duplicate profiles @@ -295,6 +303,7 @@ We're committed to providing a welcoming and inclusive environment. Please be re ### CI/CD Checks Every pull request runs automated checks: + - **Linting**: Ensures YAML syntax is correct - **Build Test**: Verifies the site builds successfully - **Pre-commit Hooks**: Checks code quality @@ -311,7 +320,8 @@ If checks fail, you'll see error messages in the PR. Fix the issues and push aga **Problem**: Your YAML file has syntax errors. -**Solution**: +**Solution**: + - Check for proper indentation (use spaces, not tabs) - Ensure colons have a space after them (`name: John`, not `name:John`) - Use `|` for multi-line bio text @@ -321,7 +331,8 @@ If checks fail, you'll see error messages in the PR. Fix the issues and push aga **Problem**: The `github` field doesn't match a real GitHub profile. -**Solution**: +**Solution**: + - Ensure you're using your exact GitHub username - Check for typos - Username is case-sensitive in this field @@ -331,6 +342,7 @@ If checks fail, you'll see error messages in the PR. Fix the issues and push aga **Problem**: File naming or format issue. **Solution**: + - File must be in `src/users/` directory - File must be named `username.yaml` (lowercase, with `.yaml` extension) - All required fields must be filled in @@ -340,6 +352,7 @@ If checks fail, you'll see error messages in the PR. Fix the issues and push aga **Problem**: Code quality checks didn't pass. **Solution**: + ```bash # Install pre-commit pip install pre-commit @@ -350,22 +363,22 @@ pre-commit run --all-files ### FAQ -**Q: Can I update my profile after it's merged?** +**Q: Can I update my profile after it's merged?** A: Yes! Just create a new PR with updates to your YAML file. -**Q: How long does review take?** +**Q: How long does review take?** A: Usually within 24-48 hours, depending on maintainer availability. -**Q: Can I add multiple social links?** +**Q: Can I add multiple social links?** A: Yes, all social fields (twitter, linkedin, instagram) are optional and independent. -**Q: What if I don't have a personal website?** +**Q: What if I don't have a personal website?** A: No problem! Just omit the `website` field or set it to your GitHub profile. -**Q: Can I use emojis in my profile?** +**Q: Can I use emojis in my profile?** A: Yes, emojis are supported in the `name` and `bio` fields! ๐ -**Q: Is there a character limit for the bio?** +**Q: Is there a character limit for the bio?** A: No hard limit, but keep it concise (2-4 paragraphs recommended). --- @@ -374,7 +387,8 @@ A: No hard limit, but keep it concise (2-4 paragraphs recommended). This project is licensed under the **GNU General Public License v3.0** - see the [LICENSE](LICENSE) file for details. -### What this means: +### What this means + - โ You can freely use, modify, and distribute this code - โ You must disclose source code when distributing - โ Changes must also be GPL-3.0 licensed @@ -396,5 +410,3 @@ This project is licensed under the **GNU General Public License v3.0** - see the - **Report bugs**: [Open an issue](https://github.com/jbampton/NextCommunity.github.io/issues) - **Ask questions**: [Start a discussion](https://github.com/jbampton/NextCommunity.github.io/discussions) - **Maintainer**: [@jbampton](https://github.com/jbampton) - - diff --git a/src/_data/build.js b/src/_data/build.js index 55cf1ba6..7f753a25 100644 --- a/src/_data/build.js +++ b/src/_data/build.js @@ -1,18 +1,18 @@ -const { execSync } = require('child_process'); +const { execSync } = require("child_process"); module.exports = () => { const now = new Date(); // Format the date: "Jan 26, 2026, 07:51 AM" - const timestamp = now.toLocaleString('en-US', { - dateStyle: 'medium', - timeStyle: 'short', + const timestamp = now.toLocaleString("en-US", { + dateStyle: "medium", + timeStyle: "short", }); - let gitHash = 'development'; + let gitHash = "development"; try { // Get the short git hash (first 7 characters) - gitHash = execSync('git rev-parse --short HEAD').toString().trim(); + gitHash = execSync("git rev-parse --short HEAD").toString().trim(); } catch (e) { console.warn("Could not fetch git hash, defaulting to 'development'"); } @@ -20,6 +20,6 @@ module.exports = () => { return { timestamp, hash: gitHash, - repoUrl: "https://github.com/NextCommunity/NextCommunity.github.io" + repoUrl: "https://github.com/NextCommunity/NextCommunity.github.io", }; }; diff --git a/src/assets/css/style.css b/src/assets/css/style.css index a5ad7bef..b4d534c6 100644 --- a/src/assets/css/style.css +++ b/src/assets/css/style.css @@ -12,7 +12,8 @@ --accent-light: #eff6ff; --accent-rgb: 37, 99, 235; --danger: #dc2626; - --card-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + --card-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), + 0 2px 4px -1px rgba(0, 0, 0, 0.06); } .dark { @@ -28,17 +29,18 @@ --card-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5); } -html, body { +html, +body { overflow-x: clip; min-height: 100%; background-color: var(--bg-page); color: var(--text-main); - transition: background-color 0.4s ease, color 0.4s ease; + transition: + background-color 0.4s ease, + color 0.4s ease; scroll-behavior: smooth; } - - /** * 2. USER CARDS - DYNAMIC & STATIC */ @@ -52,7 +54,9 @@ html, body { font-weight: 800; text-decoration: none; /* Animate ONLY the color property when theme changes */ - transition: color 0.4s ease, opacity 0.2s ease; + transition: + color 0.4s ease, + opacity 0.2s ease; } /* Static Hover: No movement */ @@ -68,10 +72,10 @@ html, body { /* Button to trigger Screenshot Mode in the Dev Panel */ .screenshot-btn { - border-color: var(--text-muted) !important; - color: var(--text-muted) !important; - font-size: 0.6rem !important; - margin-top: 10px; + border-color: var(--text-muted) !important; + color: var(--text-muted) !important; + font-size: 0.6rem !important; + margin-top: 10px; } /* If your links look like tags/pills */ @@ -88,8 +92,6 @@ html, body { border-color: var(--accent); } - - /* If you have a specific button-style profile link */ .profile-btn { background-color: var(--accent-light) !important; @@ -156,7 +158,9 @@ html, body { overflow: hidden; } -.dark .surprise-btn { background-color: var(--accent) !important; } +.dark .surprise-btn { + background-color: var(--accent) !important; +} .surprise-btn:hover { transform: translateY(-2px); @@ -164,19 +168,28 @@ html, body { filter: brightness(1.1); } -.surprise-btn::after, .skill-item::after { - content: ''; +.surprise-btn::after, +.skill-item::after { + content: ""; position: absolute; top: 0; left: -150%; width: 100%; height: 100%; - background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4), transparent); + background: linear-gradient( + 90deg, + transparent, + rgba(255, 255, 255, 0.4), + transparent + ); transform: skewX(-20deg); transition: 0.6s cubic-bezier(0.19, 1, 0.22, 1); } -.surprise-btn:hover::after, .skill-item:hover::after { left: 150%; } +.surprise-btn:hover::after, +.skill-item:hover::after { + left: 150%; +} /** * 4. DEVELOPER TOOLS - INDESTRUCTIBLE VIEWPORT PANEL @@ -204,20 +217,20 @@ html, body { /* NUCLEAR LOCK: Forces stability during page-wide glitches */ #dev-tools[data-lock="true"], html body #dev-tools[data-lock="true"] { - display: block !important; - visibility: visible !important; - opacity: 1 !important; - position: fixed !important; - top: 1rem !important; - right: 1rem !important; - transform: none !important; - animation: none !important; - border-left-color: #ef4444 !important; - box-shadow: 0 0 40px rgba(239, 68, 68, 0.6) !important; + display: block !important; + visibility: visible !important; + opacity: 1 !important; + position: fixed !important; + top: 1rem !important; + right: 1rem !important; + transform: none !important; + animation: none !important; + border-left-color: #ef4444 !important; + box-shadow: 0 0 40px rgba(239, 68, 68, 0.6) !important; } #dev-tools button { - font-family: 'JetBrains Mono', monospace; + font-family: "JetBrains Mono", monospace; font-size: 0.75rem; background: rgba(255, 255, 255, 0.03); color: #e2e8f0; @@ -238,22 +251,38 @@ html body #dev-tools[data-lock="true"] { } /* Console Neon Overrides */ -#dev-tools button[onclick*="matrix"] { color: #00ff41 !important; } -#dev-tools button[onclick*="konami"] { color: #ffcc00 !important; } -#dev-tools button[onclick*="gravity"] { color: #ff3333 !important; } -#dev-tools button[onclick*="badge_click"] { color: #bc13fe !important; } +#dev-tools button[onclick*="matrix"] { + color: #00ff41 !important; +} +#dev-tools button[onclick*="konami"] { + color: #ffcc00 !important; +} +#dev-tools button[onclick*="gravity"] { + color: #ff3333 !important; +} +#dev-tools button[onclick*="badge_click"] { + color: #bc13fe !important; +} /** * 5. SELF DESTRUCT & REPAIR */ #destruct-bar-container { - width: 100%; height: 14px; background: #000; - border: 2px solid #333; margin-top: 15px; border-radius: 4px; + width: 100%; + height: 14px; + background: #000; + border: 2px solid #333; + margin-top: 15px; + border-radius: 4px; } #destruct-bar-progress { - height: 100%; width: 0%; background: #22c55e; - transition: width 1s linear, background-color 0.3s; + height: 100%; + width: 0%; + background: #22c55e; + transition: + width 1s linear, + background-color 0.3s; } #repair-btn { @@ -266,7 +295,8 @@ html body #dev-tools[data-lock="true"] { box-shadow: 0 0 60px rgba(37, 99, 235, 0.6); z-index: 10001; position: fixed; - top: 50%; left: 50%; + top: 50%; + left: 50%; transform: translate(-50%, -50%); } @@ -274,467 +304,558 @@ html body #dev-tools[data-lock="true"] { * 6. ANIMATIONS */ @keyframes shake-anim { - 0% { transform: translate(0, 0); } - 25% { transform: translate(3px, -3px); } - 50% { transform: translate(-3px, 3px); } - 100% { transform: translate(0, 0); } + 0% { + transform: translate(0, 0); + } + 25% { + transform: translate(3px, -3px); + } + 50% { + transform: translate(-3px, 3px); + } + 100% { + transform: translate(0, 0); + } +} + +.glitch-shake { + animation: shake-anim 0.1s infinite; + overflow: hidden; } -.glitch-shake { animation: shake-anim 0.1s infinite; overflow: hidden; } - @keyframes konami-barrel-roll { - 0% { transform: rotate(0deg) scale(1); filter: hue-rotate(0deg); } - 50% { transform: rotate(180deg) scale(0.8); filter: hue-rotate(180deg); } - 100% { transform: rotate(360deg) scale(1); filter: hue-rotate(360deg); } + 0% { + transform: rotate(0deg) scale(1); + filter: hue-rotate(0deg); + } + 50% { + transform: rotate(180deg) scale(0.8); + filter: hue-rotate(180deg); + } + 100% { + transform: rotate(360deg) scale(1); + filter: hue-rotate(360deg); + } } -.konami-roll { animation: konami-barrel-roll 2s cubic-bezier(0.45, 0.05, 0.55, 0.95); } +.konami-roll { + animation: konami-barrel-roll 2s cubic-bezier(0.45, 0.05, 0.55, 0.95); +} /** * FANCY USER SELECTION EFFECT */ @keyframes fancy-ping { - 0% { - box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0.7); - } - 70% { - box-shadow: 0 0 0 20px rgba(var(--accent-rgb), 0); - } - 100% { - box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0); - } + 0% { + box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0.7); + } + 70% { + box-shadow: 0 0 0 20px rgba(var(--accent-rgb), 0); + } + 100% { + box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0); + } } /* Ensure the card can show the trace glow */ .user-card.selected-fancy { - z-index: 50; - overflow: visible !important; - transform: scale(1.02); - transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); + z-index: 50; + overflow: visible !important; + transform: scale(1.02); + transition: transform 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); } .border-trace { - position: absolute; - inset: -2px; /* Slightly outside the card border */ - width: calc(100% + 4px); - height: calc(100% + 4px); - pointer-events: none; - fill: none; + position: absolute; + inset: -2px; /* Slightly outside the card border */ + width: calc(100% + 4px); + height: calc(100% + 4px); + pointer-events: none; + fill: none; } .border-trace rect { - stroke-width: 4px; - stroke-linecap: round; - /* Perimeter length - 2500px is a safe bet for these cards */ - stroke-dasharray: 2500; - stroke-dashoffset: 2500; - animation: retrace-sequence 7.5s linear forwards; + stroke-width: 4px; + stroke-linecap: round; + /* Perimeter length - 2500px is a safe bet for these cards */ + stroke-dasharray: 2500; + stroke-dashoffset: 2500; + animation: retrace-sequence 7.5s linear forwards; } @keyframes retrace-sequence { - 0% { - stroke-dashoffset: 2500; - stroke: var(--accent); - filter: drop-shadow(0 0 8px var(--accent)); - } - 100% { - stroke-dashoffset: 0; - /* Cycle through colors while drawing */ - stroke: var(--accent); - filter: drop-shadow(0 0 12px var(--accent)) hue-rotate(360deg); - } + 0% { + stroke-dashoffset: 2500; + stroke: var(--accent); + filter: drop-shadow(0 0 8px var(--accent)); + } + 100% { + stroke-dashoffset: 0; + /* Cycle through colors while drawing */ + stroke: var(--accent); + filter: drop-shadow(0 0 12px var(--accent)) hue-rotate(360deg); + } } /* Visual feedback when hovering a skill to gain XP */ .mining-xp { - filter: brightness(1.5); - box-shadow: 0 0 15px var(--accent); - transition: all 0.2s ease; + filter: brightness(1.5); + box-shadow: 0 0 15px var(--accent); + transition: all 0.2s ease; } /* Special styling for those who have reached Level 5 (Data Miner) */ body[data-level="5"] .skill-item { - border-color: #06b6d4 !important; /* Data Miner Cyan */ - background: rgba(6, 182, 212, 0.1) !important; - position: relative; - overflow: hidden; + border-color: #06b6d4 !important; /* Data Miner Cyan */ + background: rgba(6, 182, 212, 0.1) !important; + position: relative; + overflow: hidden; } /* Add a gem-like sparkle to skills at Level 5 */ body[data-level="5"] .skill-item::before { - content: ''; - position: absolute; - top: -50%; - left: -50%; - width: 200%; - height: 200%; - background: linear-gradient(45deg, transparent, rgba(255,255,255,0.3), transparent); - transform: rotate(45deg); - animation: gem-shimmer 3s infinite; + content: ""; + position: absolute; + top: -50%; + left: -50%; + width: 200%; + height: 200%; + background: linear-gradient( + 45deg, + transparent, + rgba(255, 255, 255, 0.3), + transparent + ); + transform: rotate(45deg); + animation: gem-shimmer 3s infinite; } @keyframes gem-shimmer { - 0% { transform: translateX(-100%) rotate(45deg); } - 100% { transform: translateX(100%) rotate(45deg); } + 0% { + transform: translateX(-100%) rotate(45deg); + } + 100% { + transform: translateX(100%) rotate(45deg); + } } @keyframes float-up { - 0% { transform: translate(-50%, 0); opacity: 1; } - 100% { transform: translate(-50%, -50px); opacity: 0; } + 0% { + transform: translate(-50%, 0); + opacity: 1; + } + 100% { + transform: translate(-50%, -50px); + opacity: 0; + } } /* Level 5 Specific Visual Perk */ .level-architect .skill-item, body[data-level="5"] .skill-item { - border-color: #06b6d4 !important; - background: rgba(6, 182, 212, 0.1) !important; - box-shadow: 0 0 10px rgba(6, 182, 212, 0.2); + border-color: #06b6d4 !important; + background: rgba(6, 182, 212, 0.1) !important; + box-shadow: 0 0 10px rgba(6, 182, 212, 0.2); } .skill-item { - cursor: crosshair; /* Makes it feel like you are "mining" */ + cursor: crosshair; /* Makes it feel like you are "mining" */ } /* Level 6 Visuals */ body[data-level="6"] .user-card { - border-color: rgba(236, 72, 153, 0.3); + border-color: rgba(236, 72, 153, 0.3); } body[data-level="6"]::after { - content: ""; - position: fixed; - top: 0; - left: 0; - width: 100vw; - height: 100vh; - background: linear-gradient( - rgba(18, 16, 16, 0) 50%, - rgba(0, 0, 0, 0.1) 50% - ); - background-size: 100% 4px; - z-index: 9999; - pointer-events: none; - opacity: 0.2; /* Very subtle scanlines */ + content: ""; + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.1) 50%); + background-size: 100% 4px; + z-index: 9999; + pointer-events: none; + opacity: 0.2; /* Very subtle scanlines */ } /* Added via JS when XP increases */ .xp-pulse { - transform: scale(1.3); - color: white !important; + transform: scale(1.3); + color: white !important; } #jump-lvl { - font-family: 'Courier New', monospace; - text-shadow: 0 0 5px var(--accent); -}/* Ensure the text inside the jump box is always visible */ + font-family: "Courier New", monospace; + text-shadow: 0 0 5px var(--accent); +} /* Ensure the text inside the jump box is always visible */ #jump-lvl { - appearance: textfield; /* Removes default arrows */ - -webkit-appearance: none; - line-height: 30px !important; + appearance: textfield; /* Removes default arrows */ + -webkit-appearance: none; + line-height: 30px !important; } #jump-lvl::placeholder { - color: rgba(0, 255, 204, 0.3) !important; + color: rgba(0, 255, 204, 0.3) !important; } /* Force standard text color even on focus */ #jump-lvl:focus { - outline: 2px solid #00ffcc !important; - background-color: #000 !important; - color: #00ffcc !important; + outline: 2px solid #00ffcc !important; + background-color: #000 !important; + color: #00ffcc !important; } /* Base Force Aura Animation */ @keyframes force-pulse { - 0% { transform: scale(1); filter: brightness(1) drop-shadow(0 0 5px var(--glow-color)); } - 50% { transform: scale(1.1); filter: brightness(1.4) drop-shadow(0 0 20px var(--glow-color)); } - 100% { transform: scale(1); filter: brightness(1) drop-shadow(0 0 5px var(--glow-color)); } + 0% { + transform: scale(1); + filter: brightness(1) drop-shadow(0 0 5px var(--glow-color)); + } + 50% { + transform: scale(1.1); + filter: brightness(1.4) drop-shadow(0 0 20px var(--glow-color)); + } + 100% { + transform: scale(1); + filter: brightness(1) drop-shadow(0 0 5px var(--glow-color)); + } } /* The Active Class */ .force-glow { - --glow-color: #38bdf8; /* Default Jedi Blue */ - position: relative; - z-index: 10; - transition: all 0.3s ease; - animation: force-pulse 5s infinite ease-in-out; + --glow-color: #38bdf8; /* Default Jedi Blue */ + position: relative; + z-index: 10; + transition: all 0.3s ease; + animation: force-pulse 5s infinite ease-in-out; } /* Sith Variant (Red Glow) */ -[data-level^="13"], [data-level^="14"], [data-level^="15"] .force-glow { - --glow-color: #ef4444; /* Sith Red */ +[data-level^="13"], +[data-level^="14"], +[data-level^="15"] .force-glow { + --glow-color: #ef4444; /* Sith Red */ } /* Ensure the parent container has a background so you can see the 'empty' part */ #game-stats .bg-black\/10 { - background-color: rgba(0, 0, 0, 0.1) !important; - min-width: 80px; /* Ensure it hasn't collapsed to 0 width */ - height: 6px; + background-color: rgba(0, 0, 0, 0.1) !important; + min-width: 80px; /* Ensure it hasn't collapsed to 0 width */ + height: 6px; } /* Ensure the progress bar itself has a height and a visible color */ #level-progress { - height: 100%; - background-color: var(--accent); /* This is the level color */ - transition: width 0.3s ease-in-out !important; /* Make it smooth */ - display: block !important; + height: 100%; + background-color: var(--accent); /* This is the level color */ + transition: width 0.3s ease-in-out !important; /* Make it smooth */ + display: block !important; } /* Force Glow for the Badge */ @keyframes force-pulse { - 0% { filter: drop-shadow(0 0 2px var(--accent)); transform: scale(1); } - 50% { filter: drop-shadow(0 0 15px var(--accent)); transform: scale(1.1); } - 100% { filter: drop-shadow(0 0 2px var(--accent)); transform: scale(1); } + 0% { + filter: drop-shadow(0 0 2px var(--accent)); + transform: scale(1); + } + 50% { + filter: drop-shadow(0 0 15px var(--accent)); + transform: scale(1.1); + } + 100% { + filter: drop-shadow(0 0 2px var(--accent)); + transform: scale(1); + } } .force-glow { - animation: force-pulse 1.5s infinite ease-in-out; + animation: force-pulse 1.5s infinite ease-in-out; } #level-name { - font-weight: 900; - text-transform: uppercase; - letter-spacing: 0.02em; + font-weight: 900; + text-transform: uppercase; + letter-spacing: 0.02em; - /* Remove any existing filters that cause fuzziness */ - filter: none !important; - transition: color 0.3s ease; + /* Remove any existing filters that cause fuzziness */ + filter: none !important; + transition: color 0.3s ease; } /* Adjust the stroke for Dark/Random themes to keep it crisp */ .dark #level-name { - text-shadow: 1px 1px 0px rgba(0,0,0,0.5); + text-shadow: 1px 1px 0px rgba(0, 0, 0, 0.5); } #level-badge { - transition: background-color 0.4s ease, transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); + transition: + background-color 0.4s ease, + transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275); } /* Ensure the XP numbers are always legible */ #total-xp-display { - color: var(--text-main); - filter: brightness(1.2); /* Pops slightly more in dark mode */ + color: var(--text-main); + filter: brightness(1.2); /* Pops slightly more in dark mode */ } /* Progress bar should always have a high-contrast background */ .xp-bar-container { - background: rgba(0, 0, 0, 0.1); + background: rgba(0, 0, 0, 0.1); } .dark .xp-bar-container { - background: rgba(255, 255, 255, 0.1); + background: rgba(255, 255, 255, 0.1); } .xp-popup { - position: absolute; - pointer-events: none; - z-index: 9999; - animation: floatUp 1s ease-out forwards; - color: var(--accent); /* This uses our dynamic level color! */ - font-size: 0.75rem; + position: absolute; + pointer-events: none; + z-index: 9999; + animation: floatUp 1s ease-out forwards; + color: var(--accent); /* This uses our dynamic level color! */ + font-size: 0.75rem; } @keyframes floatUp { - 0% { - transform: translateY(0); - opacity: 1; - } - 100% { - transform: translateY(-50px); - opacity: 0; - } + 0% { + transform: translateY(0); + opacity: 1; + } + 100% { + transform: translateY(-50px); + opacity: 0; + } } @keyframes xpFloat { - 0% { - transform: translateY(0) scale(1); - opacity: 1; - } - 100% { - transform: translateY(-40px) scale(1.2); - opacity: 0; - } + 0% { + transform: translateY(0) scale(1); + opacity: 1; + } + 100% { + transform: translateY(-40px) scale(1.2); + opacity: 0; + } } .animate-xp-float { - animation: xpFloat 1s ease-out forwards; - /* This makes sure the text is crisp on light/dark themes */ - text-shadow: 0 0 4px rgba(0,0,0,0.3); + animation: xpFloat 1s ease-out forwards; + /* This makes sure the text is crisp on light/dark themes */ + text-shadow: 0 0 4px rgba(0, 0, 0, 0.3); } - - /* Username: Big, bold, and using the random accent */ -.developer-name, h1 { - color: var(--accent); - text-shadow: 0 0 20px hsla(var(--accent-hue), 90%, 65%, 0.3); +.developer-name, +h1 { + color: var(--accent); + text-shadow: 0 0 20px hsla(var(--accent-hue), 90%, 65%, 0.3); } /* Skills: Give them a 'glass' look using the random background */ .skill-tag { - background: var(--bg-card); - border: 1px solid var(--border-color); - color: var(--text-main); + background: var(--bg-card); + border: 1px solid var(--border-color); + color: var(--text-main); } .skill-tag:hover { - border-color: var(--accent); - color: var(--accent); - box-shadow: 0 0 15px var(--accent); + border-color: var(--accent); + color: var(--accent); + box-shadow: 0 0 15px var(--accent); } /* Links: Make them pop! */ a { - color: var(--accent); - transition: all 0.2s ease; + color: var(--accent); + transition: all 0.2s ease; } a:hover { - filter: brightness(1.2); - text-decoration: underline; + filter: brightness(1.2); + text-decoration: underline; } @keyframes badgePop { - 0% { transform: scale(1); filter: brightness(1); } - 50% { transform: scale(1.4); filter: brightness(1.5); } - 100% { transform: scale(1); filter: brightness(1); } + 0% { + transform: scale(1); + filter: brightness(1); + } + 50% { + transform: scale(1.4); + filter: brightness(1.5); + } + 100% { + transform: scale(1); + filter: brightness(1); + } } .animate-badge-pop { - animation: badgePop 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; - z-index: 101; /* Ensure it pops above the header bar */ + animation: badgePop 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; + z-index: 101; /* Ensure it pops above the header bar */ } /* Optional: Add a glow to the level number too */ #level-number { - transition: all 0.3s ease; + transition: all 0.3s ease; } .animate-badge-pop #level-number { - color: white; - text-shadow: 0 0 10px rgba(255,255,255,1); + color: white; + text-shadow: 0 0 10px rgba(255, 255, 255, 1); } - - .level-up-toast { - position: fixed; - top: 20px; - left: 50%; - transform: translateX(-50%); - background: rgba(15, 23, 42, 0.9); /* Dark background for contrast */ - backdrop-filter: blur(10px); - border: 1px solid rgba(255, 255, 255, 0.1); - padding: 16px 24px; - border-radius: 12px; - box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5), - 0 0 15px var(--accent); /* Glow matches current level */ - z-index: 1000; - animation: slideDownIn 0.5s cubic-bezier(0.18, 0.89, 0.32, 1.28) forwards; + position: fixed; + top: 20px; + left: 50%; + transform: translateX(-50%); + background: rgba(15, 23, 42, 0.9); /* Dark background for contrast */ + backdrop-filter: blur(10px); + border: 1px solid rgba(255, 255, 255, 0.1); + padding: 16px 24px; + border-radius: 12px; + box-shadow: + 0 10px 25px -5px rgba(0, 0, 0, 0.5), + 0 0 15px var(--accent); /* Glow matches current level */ + z-index: 1000; + animation: slideDownIn 0.5s cubic-bezier(0.18, 0.89, 0.32, 1.28) forwards; } .toast-content { - display: flex; - align-items: center; - gap: 16px; + display: flex; + align-items: center; + gap: 16px; } .toast-emoji { - font-size: 2rem; + font-size: 2rem; } .toast-title { - color: #94a3b8; - font-size: 0.7rem; - font-weight: 800; - letter-spacing: 0.1rem; - margin: 0; + color: #94a3b8; + font-size: 0.7rem; + font-weight: 800; + letter-spacing: 0.1rem; + margin: 0; } .toast-rank { - font-size: 1.25rem; - font-weight: 900; - margin: 0; - text-transform: uppercase; + font-size: 1.25rem; + font-weight: 900; + margin: 0; + text-transform: uppercase; } @keyframes slideDownIn { - from { transform: translate(-50%, -100px); opacity: 0; } - to { transform: translate(-50%, 0); opacity: 1; } + from { + transform: translate(-50%, -100px); + opacity: 0; + } + to { + transform: translate(-50%, 0); + opacity: 1; + } } .fade-out { - opacity: 0; - transform: translate(-50%, -20px); - transition: all 0.5s ease; + opacity: 0; + transform: translate(-50%, -20px); + transition: all 0.5s ease; } .matrix-alert { - position: fixed; - bottom: 20%; - right: 20px; - background: rgba(0, 0, 0, 0.9); - border-left: 4px solid #10b981; - color: #10b981; - padding: 15px; - font-family: 'Courier New', monospace; - z-index: 2000; - box-shadow: 0 0 20px rgba(16, 185, 129, 0.2); - animation: matrixSlideIn 0.3s ease-out; + position: fixed; + bottom: 20%; + right: 20px; + background: rgba(0, 0, 0, 0.9); + border-left: 4px solid #10b981; + color: #10b981; + padding: 15px; + font-family: "Courier New", monospace; + z-index: 2000; + box-shadow: 0 0 20px rgba(16, 185, 129, 0.2); + animation: matrixSlideIn 0.3s ease-out; } @keyframes matrixSlideIn { - from { transform: translateX(100%); opacity: 0; } - to { transform: translateX(0); opacity: 1; } + from { + transform: translateX(100%); + opacity: 0; + } + to { + transform: translateX(0); + opacity: 1; + } } #matrix-console-output { - /* Subtle green glow on text */ - text-shadow: 0 0 5px rgba(16, 185, 129, 0.3); - scroll-behavior: smooth; - display: flex; - flex-direction: column; + /* Subtle green glow on text */ + text-shadow: 0 0 5px rgba(16, 185, 129, 0.3); + scroll-behavior: smooth; + display: flex; + flex-direction: column; } /* Custom scrollbar for the terminal */ #matrix-console-output::-webkit-scrollbar { - width: 3px; + width: 3px; } #matrix-console-output::-webkit-scrollbar-thumb { - background: rgba(16, 185, 129, 0.3); + background: rgba(16, 185, 129, 0.3); } /* The Matrix Line Animation */ .matrix-line { - border-left: 2px solid #10b981; - padding-left: 8px; - margin-bottom: 4px; - animation: matrixLineFade 0.3s ease-out; + border-left: 2px solid #10b981; + padding-left: 8px; + margin-bottom: 4px; + animation: matrixLineFade 0.3s ease-out; } @keyframes matrixLineFade { - from { opacity: 0; transform: translateX(-10px); } - to { opacity: 1; transform: translateX(0); } + from { + opacity: 0; + transform: translateX(-10px); + } + to { + opacity: 1; + transform: translateX(0); + } } /* Maximize State */ .console-maximized { - width: 90vw !important; - height: auto !important; - bottom: 5vh !important; - right: 5vw !important; - left: 5vw !important; - z-index: 2000 !important; + width: 90vw !important; + height: auto !important; + bottom: 5vh !important; + right: 5vw !important; + left: 5vw !important; + z-index: 2000 !important; } #matrix-console-output { - scrollbar-width: thin; - scrollbar-color: #10b981 transparent; + scrollbar-width: thin; + scrollbar-color: #10b981 transparent; } /* Add a scanline effect for that retro terminal feel */ #matrix-console-output::before { - content: " "; - position: absolute; - top: 0; left: 0; bottom: 0; right: 0; - background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%), - linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06)); - z-index: 10; - background-size: 100% 2px, 3px 100%; - pointer-events: none; + content: " "; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%), + linear-gradient( + 90deg, + rgba(255, 0, 0, 0.06), + rgba(0, 255, 0, 0.02), + rgba(0, 0, 255, 0.06) + ); + z-index: 10; + background-size: + 100% 2px, + 3px 100%; + pointer-events: none; } .cursor-grab:active { - cursor: grabbing; + cursor: grabbing; } /* Prevents the terminal text from getting highlighted while you move the window */ #matrix-console-container.is-dragging { - user-select: none; + user-select: none; } diff --git a/src/assets/js/script.js b/src/assets/js/script.js index b7043d4d..aa5e945e 100644 --- a/src/assets/js/script.js +++ b/src/assets/js/script.js @@ -1,260 +1,283 @@ - /** * 1. LEVELS DATA (0-100) */ const LEVELS = [ - // 0-10: Original Ranks - { level: 0, name: "Newbie", emoji: "๐ฃ", color: "#94a3b8" }, - { level: 1, name: "Script Kid", emoji: "๐น", color: "#10b981" }, - { level: 2, name: "Code Breaker", emoji: "๐ต๏ธโโ๏ธ", color: "#f59e0b" }, - { level: 3, name: "Void Walker", emoji: "๐", color: "#6366f1" }, - { level: 4, name: "Bug Hunter", emoji: "๐", color: "#84cc16" }, - { level: 5, name: "Data Miner", emoji: "๐", color: "#06b6d4" }, - { level: 6, name: "Sys Admin", emoji: "๐ ๏ธ", color: "#ec4899" }, - { level: 7, name: "Terminal Pro", emoji: "โจ๏ธ", color: "#7c3aed" }, - { level: 8, name: "Cloud Expert", emoji: "โ๏ธ", color: "#3b82f6" }, - { level: 9, name: "Full Stack", emoji: "๐ฅ", color: "#f97316" }, - { level: 10, name: "Architect", emoji: "๐", color: "#ef4444" }, - - // 11-30: Magic the Gathering (Creatures & Keywords) - { level: 11, name: "Llanowar Elf", emoji: "๐น", color: "#2d5a27" }, - { level: 12, name: "Scryer", emoji: "๐ฎ", color: "#1d4ed8" }, - { level: 13, name: "Trampler", emoji: "๐", color: "#15803d" }, - { level: 14, name: "Flying Menace", emoji: "๐ฆ", color: "#4a044e" }, - { level: 15, name: "Mana Leech", emoji: "๐ง", color: "#0ea5e9" }, - { level: 16, name: "Spellcounter", emoji: "๐ซ", color: "#2563eb" }, - { level: 17, name: "Goblin Guide", emoji: "๐บ", color: "#dc2626" }, - { level: 18, name: "Serum Visionary", emoji: "๐งช", color: "#6366f1" }, - { level: 19, name: "Mythic Rare", emoji: "๐ ", color: "#f97316" }, - { level: 20, name: "Planeswalker", emoji: "โจ", color: "#fbbf24" }, - - // 21-40: Game of Thrones (Houses & Heroes) - { level: 21, name: "Night's Watch", emoji: "๐ฆ ", color: "#1e293b" }, - { level: 22, name: "Wildling Scout", emoji: "โ๏ธ", color: "#94a3b8" }, - { level: 23, name: "Ironborn", emoji: "โ", color: "#475569" }, - { level: 24, name: "Dothraki Rider", emoji: "๐", color: "#b45309" }, - { level: 25, name: "Kingslayer", emoji: "๐ก๏ธ", color: "#facc15" }, - { level: 26, name: "Winterfell Warden", emoji: "๐บ", color: "#cbd5e1" }, - { level: 27, name: "Dragonstone Guard", emoji: "๐", color: "#991b1b" }, - { level: 28, name: "Faceless Man", emoji: "๐ญ", color: "#4b5563" }, - { level: 29, name: "Hand of the King", emoji: "๐๏ธ", color: "#d97706" }, - { level: 30, name: "Iron Throne Heir", emoji: "โ๏ธ", color: "#111827" }, - - // 31-50: Wheel of Time (The Tiers of Power) - { level: 31, name: "Two Rivers Archer", emoji: "๐น", color: "#166534" }, - { level: 32, name: "Gleeman", emoji: "๐ถ", color: "#be185d" }, - { level: 33, name: "Borderlander", emoji: "๐ก๏ธ", color: "#991b1b" }, - { level: 34, name: "Warders Bond", emoji: "๐", color: "#1e293b" }, - { level: 35, name: "Aes Sedai Novice", emoji: "๐ฏ๏ธ", color: "#f8fafc" }, - { level: 36, name: "Accepted", emoji: "๐", color: "#e2e8f0" }, - { level: 37, name: "Aiel Dreamwalker", emoji: "๐๏ธ", color: "#d97706" }, - { level: 38, name: "Asha'man", emoji: "โก", color: "#000000" }, - { level: 39, name: "Amyrlin Seat", emoji: "๐", color: "#ffffff" }, - { level: 40, name: "Ta'veren", emoji: "๐", color: "#6366f1" }, - - // 41-60: Lord of the Rings (Fellowship & Foes) - { level: 41, name: "Hobbit Adventurer", emoji: "๐บ", color: "#15803d" }, - { level: 42, name: "Bree Strider", emoji: "๐ข", color: "#451a03" }, - { level: 43, name: "Riddermark Lord", emoji: "๐", color: "#166534" }, - { level: 44, name: "Gondor Soldier", emoji: "๐ก๏ธ", color: "#94a3b8" }, - { level: 45, name: "Uruk-hai Berserker", emoji: "โ", color: "#450a0a" }, - { level: 46, name: "Elven Archer", emoji: "๐", color: "#4ade80" }, - { level: 47, name: "Dwarf Warrior", emoji: "โ๏ธ", color: "#78350f" }, - { level: 48, name: "Nazgรปl Rider", emoji: "๐", color: "#020617" }, - { level: 49, name: "Istari Pupil", emoji: "๐ง", color: "#3b82f6" }, - { level: 50, name: "Ring-bearer", emoji: "๐", color: "#fbbf24" }, - - // NEW LEVELS 51-60 - { level: 51, name: "White Wizard", emoji: "๐งโโ๏ธ", color: "#f8fafc" }, - { level: 52, name: "Silmaril Seeker", emoji: "๐", color: "#7dd3fc" }, - { level: 53, name: "Dune Walker", emoji: "โณ", color: "#fcd34d" }, - { level: 54, name: "Shadowfax Rider", emoji: "๐", color: "#e2e8f0" }, - { level: 55, name: "Master of Coin", emoji: "๐ช", color: "#fbbf24" }, - { level: 56, name: "Kingsguard", emoji: "๐ก๏ธ", color: "#94a3b8" }, - { level: 57, name: "Valyrian Smith", emoji: "โ๏ธ", color: "#475569" }, - { level: 58, name: "Night Watcher", emoji: "๐ฆ", color: "#312e81" }, - { level: 59, name: "Obsidian Blade", emoji: "๐ก๏ธ", color: "#1e293b" }, - { level: 60, name: "Citadel Maester", emoji: "๐", color: "#8b5e3c" }, - - // 61-80: High Magic & Artifacts - { level: 61, name: "Mox Emerald", emoji: "๐", color: "#10b981" }, - { level: 62, name: "Mox Sapphire", emoji: "๐", color: "#3b82f6" }, - { level: 63, name: "Mox Ruby", emoji: "โค๏ธ", color: "#ef4444" }, - { level: 64, name: "Mox Jet", emoji: "๐ค", color: "#18181b" }, - { level: 65, name: "Mox Pearl", emoji: "๐ค", color: "#f8fafc" }, - { level: 66, name: "Black Lotus", emoji: "๐บ", color: "#000000" }, - { level: 67, name: "Balrog Slayer", emoji: "๐ฅ", color: "#f97316" }, - { level: 68, name: "Witch-king", emoji: "๐", color: "#334155" }, - { level: 69, name: "Shelob's Kin", emoji: "๐ท๏ธ", color: "#0f172a" }, - { level: 70, name: "Dragon-friend", emoji: "๐ฒ", color: "#dc2626" }, - - // NEW LEVELS 71-80 - { level: 71, name: "Neon Ghost", emoji: "๐ป", color: "#22d3ee" }, - { level: 72, name: "Dragon's Greed", emoji: "๐ช", color: "#fbbf24" }, - { level: 73, name: "Mistborn", emoji: "๐ซ๏ธ", color: "#94a3b8" }, - { level: 74, name: "Cinder Soul", emoji: "๐ฅ", color: "#f87171" }, - { level: 75, name: "High Council", emoji: "๐๏ธ", color: "#6366f1" }, - { level: 76, name: "Valyrian Steel", emoji: "๐ก๏ธ", color: "#cbd5e1" }, - { level: 77, name: "Golden Snitch", emoji: "โจ", color: "#facc15" }, - { level: 78, name: "Ether Weaver", emoji: "๐ธ๏ธ", color: "#a855f7" }, - { level: 79, name: "Star Forge", emoji: "๐จ", color: "#38bdf8" }, - { level: 80, name: "Mithril Guard", emoji: "๐ก๏ธ", color: "#e2e8f0" }, - - // 81-90: Wheel of Time (The Forsaken & Dragons) - { level: 81, name: "Lan Mandragoran", emoji: "๐ก๏ธ", color: "#1e293b" }, - { level: 82, name: "Moiraine Damodred", emoji: "๐ง", color: "#1d4ed8" }, - { level: 83, name: "Ishamael", emoji: "๐๏ธ", color: "#450a0a" }, - { level: 84, name: "Callandor Wielder", emoji: "๐", color: "#22d3ee" }, - { level: 85, name: "Lewes Therin", emoji: "โ๏ธ", color: "#fde047" }, - { level: 86, name: "Dragon Reborn", emoji: "๐", color: "#ef4444" }, - - // NEW LEVELS 87-90 - { level: 87, name: "Phoenix Down", emoji: "๐ชถ", color: "#fb7185" }, - { level: 88, name: "Void Sentinel", emoji: "๐๏ธโ๐จ๏ธ", color: "#4ade80" }, - { level: 89, name: "Elder Wand", emoji: "๐ช", color: "#94a3b8" }, - { level: 90, name: "Balrog's Whip", emoji: "๐ฅ", color: "#b91c1c" }, - - // 91-100: Cosmic Legends - { level: 91, name: "Sauron's Shadow", emoji: "๐๏ธ", color: "#000000" }, - { level: 92, name: "Galadriel's Light", emoji: "๐", color: "#e2e8f0" }, - { level: 93, name: "Eldrazi Titan", emoji: "๐", color: "#a855f7" }, - { level: 94, name: "Tom Bombadil", emoji: "๐", color: "#fbbf24" }, - { level: 95, name: "Sauron Unleashed", emoji: "๐", color: "#7f1d1d" }, - { level: 96, name: "Saruman the White", emoji: "โ", color: "#cbd5e1" }, - { level: 97, name: "Gandalf the Grey", emoji: "๐", color: "#64748b" }, - { level: 98, name: "Gandalf the White", emoji: "๐งโโ๏ธ", color: "#ffffff" }, - { level: 99, name: "The Creator", emoji: "๐", color: "#6366f1" }, - { level: 100, name: "Eru Ilรบvatar", emoji: "โจ", color: "#ffffff" }, - - { level: 101, name: "Padawan Learner", emoji: "๐ง", color: "#60a5fa" }, - { level: 102, name: "Moisture Farmer", emoji: "๐", color: "#d97706" }, - { level: 103, name: "Scrappy Scavenger", emoji: "๐ง", color: "#fcd34d" }, - { level: 104, name: "Cantina Regular", emoji: "๐น", color: "#9333ea" }, - { level: 105, name: "Holocron Finder", emoji: "๐ง", color: "#38bdf8" }, - { level: 106, name: "Speeder Racer", emoji: "๐๏ธ", color: "#fb923c" }, - { level: 107, name: "Droid Mechanic", emoji: "๐ค", color: "#94a3b8" }, - { level: 108, name: "Kyber Seeker", emoji: "๐", color: "#ffffff" }, - { level: 109, name: "Outer Rim Nomad", emoji: "๐๏ธ", color: "#a8a29e" }, - { level: 110, name: "Rebel Pilot", emoji: "๐", color: "#ef4444" }, - { level: 111, name: "Squadron Leader", emoji: "๐ก", color: "#f87171" }, - { level: 112, name: "Astromech Specialist", emoji: "๐", color: "#3b82f6" }, - { level: 113, name: "Smuggler Associate", emoji: "๐ฆ", color: "#b45309" }, - { level: 114, name: "Sabacc Champion", emoji: "๐", color: "#fbbf24" }, - { level: 115, name: "Jedi Knight", emoji: "โ๏ธ", color: "#60a5fa" }, - { level: 116, name: "Lightsaber Smith", emoji: "๐ ๏ธ", color: "#2dd4bf" }, - { level: 117, name: "Force Sensitive", emoji: "๐", color: "#818cf8" }, - { level: 118, name: "Temple Guardian", emoji: "๐ฐ", color: "#facc15" }, - { level: 119, name: "Wayseeker", emoji: "๐งญ", color: "#94a3b8" }, - { level: 120, name: "Mandalorian Initiate", emoji: "๐ก๏ธ", color: "#64748b" }, - { level: 121, name: "Foundling", emoji: "๐ถ", color: "#cbd5e1" }, - { level: 122, name: "Beskar Bearer", emoji: "๐", color: "#475569" }, - { level: 123, name: "Clan Defender", emoji: "โ๏ธ", color: "#1e293b" }, - { level: 124, name: "Jetpack Ace", emoji: "๐ฅ", color: "#f97316" }, - { level: 125, name: "Jedi Guardian", emoji: "๐ก๏ธ", color: "#22c55e" }, - - // --- IMPERIAL MIGHT: THE SHADOW (126-150) --- - { level: 126, name: "Stormtrooper Recruit", emoji: "โช", color: "#ffffff" }, - { level: 127, name: "Scout Trooper", emoji: "๐๏ธ", color: "#e2e8f0" }, - { level: 128, name: "TIE Pilot", emoji: "๐ฆ", color: "#1f2937" }, - { level: 129, name: "Imperial Officer", emoji: "๐", color: "#334155" }, - { level: 130, name: "Millennium Captain", emoji: "๐", color: "#fbbf24" }, - { level: 131, name: "Sith Acolyte", emoji: "๐", color: "#991b1b" }, - { level: 132, name: "Shadow Guard", emoji: "๐ค", color: "#000000" }, - { level: 133, name: "Inquisitor Trainee", emoji: "๐ด", color: "#dc2626" }, - { level: 134, name: "Purge Trooper", emoji: "๐งจ", color: "#450a0a" }, - { level: 135, name: "Sith Stalker", emoji: "๐ต๏ธ", color: "#7f1d1d" }, - { level: 136, name: "Red Guard", emoji: "๐ก๏ธ", color: "#b91c1c" }, - { level: 137, name: "Dark Side Adept", emoji: "๐", color: "#450606" }, - { level: 138, name: "Sith Alchemist", emoji: "๐งช", color: "#6d28d9" }, - { level: 139, name: "Holocron Corruptor", emoji: "๐ป", color: "#be123c" }, - { level: 140, name: "Imperial Inquisitor", emoji: "๐คบ", color: "#991b1b" }, - { level: 141, name: "Grand Inquisitor", emoji: "๐น", color: "#7f1d1d" }, - { level: 142, name: "Star Destroyer Commander", emoji: "๐ข", color: "#94a3b8" }, - { level: 143, name: "Super Star Destroyer Admin", emoji: "๐", color: "#64748b" }, - { level: 144, name: "Kyber Crystal Corruptor", emoji: "๐ฉธ", color: "#f43f5e" }, - { level: 145, name: "Death Star Architect", emoji: "๐ฐ๏ธ", color: "#475569" }, - { level: 146, name: "Planetary Governor", emoji: "๐ช", color: "#ca8a04" }, - { level: 147, name: "Imperial Advisor", emoji: "๐ง ", color: "#a855f7" }, - { level: 148, name: "Sith Warrior", emoji: "โ๏ธ", color: "#991b1b" }, - { level: 149, name: "Dark Disciple", emoji: "๐ฅ", color: "#dc2626" }, - { level: 150, name: "Sith Lord", emoji: "๐", color: "#000000" }, - - // --- BOUNTY HUNTERS & MERCENARIES (151-175) --- - { level: 151, name: "Guild Member", emoji: "๐", color: "#8b5e3c" }, - { level: 152, name: "Tracker", emoji: "๐ฃ", color: "#a8a29e" }, - { level: 153, name: "Sniper Specialist", emoji: "๐ฏ", color: "#ef4444" }, - { level: 154, name: "Thermal Detonator Expert", emoji: "๐ฃ", color: "#f97316" }, - { level: 155, name: "Bounty Hunter Prime", emoji: "๐๏ธ", color: "#4ade80" }, - { level: 156, name: "Carbonite Freezer", emoji: "๐ง", color: "#bae6fd" }, - { level: 157, name: "Underworld Kingpin", emoji: "๐", color: "#7c3aed" }, - { level: 158, name: "Hutt Enforcer", emoji: "๐", color: "#65a30d" }, - { level: 159, name: "Crime Syndicate Boss", emoji: "๐ผ", color: "#1e1b4b" }, - { level: 160, name: "Grand Moff", emoji: "๐ ", color: "#334155" }, - { level: 161, name: "Imperial Regent", emoji: "๐๏ธ", color: "#94a3b8" }, - { level: 162, name: "Hand of Justice", emoji: "โ๏ธ", color: "#facc15" }, - { level: 163, name: "Ancient Archivist", emoji: "๐", color: "#d97706" }, - { level: 164, name: "Dathomir Witch", emoji: "๐ฎ", color: "#db2777" }, - { level: 165, name: "Grey Jedi", emoji: "โฏ๏ธ", color: "#64748b" }, - { level: 166, name: "Balance Seeker", emoji: "๐", color: "#94a3b8" }, - { level: 167, name: "Jedi Master", emoji: "๐ง", color: "#60a5fa" }, - { level: 168, name: "Council Member", emoji: "๐ช", color: "#3b82f6" }, - { level: 169, name: "Temple Overseer", emoji: "๐๏ธ", color: "#2563eb" }, - { level: 170, name: "Jedi Sage", emoji: "๐", color: "#93c5fd" }, - { level: 171, name: "High Republic Hero", emoji: "๐", color: "#fbbf24" }, - { level: 172, name: "Living Force Vessel", emoji: "๐", color: "#4ade80" }, - { level: 173, name: "Chosen One Initiate", emoji: "โก", color: "#ffffff" }, - { level: 174, name: "Master of the Order", emoji: "๐", color: "#1d4ed8" }, - { level: 175, name: "Jedi Grand Master", emoji: "๐งโโ๏ธ", color: "#10b981" }, - - // --- THE FORCE SUPREME (176-200) --- - { level: 176, name: "Dark Side Entity", emoji: "๐", color: "#111827" }, - { level: 177, name: "Life Force Leecher", emoji: "๐ฉธ", color: "#7f1d1d" }, - { level: 178, name: "Sith Emperor", emoji: "๐", color: "#000000" }, - { level: 179, name: "World Eater", emoji: "๐", color: "#4c0519" }, - { level: 180, name: "Darth Vader's Wrath", emoji: "๐บ", color: "#b91c1c" }, - { level: 181, name: "Unstoppable Force", emoji: "๐ช๏ธ", color: "#ffffff" }, - { level: 182, name: "Immovable Object", emoji: "๐ฟ", color: "#475569" }, - { level: 183, name: "Force Projection", emoji: "โจ", color: "#7dd3fc" }, - { level: 184, name: "Voice of the Force", emoji: "๐ฃ๏ธ", color: "#e2e8f0" }, - { level: 185, name: "Emperor's Hand", emoji: "โก", color: "#a855f7" }, - { level: 186, name: "Force Stormbringer", emoji: "๐ฉ๏ธ", color: "#38bdf8" }, - { level: 187, name: "Space-Time Weaver", emoji: "๐ธ๏ธ", color: "#c084fc" }, - { level: 188, name: "World Between Worlds Explorer", emoji: "๐", color: "#a5b4fc" }, - { level: 189, name: "Cosmic Sentinel", emoji: "๐๏ธ", color: "#2dd4bf" }, - { level: 190, name: "Force Ghost", emoji: "๐ป", color: "#bae6fd" }, - { level: 191, name: "Ethereal Guide", emoji: "๐ฏ๏ธ", color: "#ffffff" }, - { level: 192, name: "Midi-chlorian Master", emoji: "๐งฌ", color: "#4ade80" }, - { level: 193, name: "Force Nexus", emoji: "๐", color: "#facc15" }, - { level: 194, name: "Ancient One", emoji: "โณ", color: "#d97706" }, - { level: 195, name: "The Son & The Daughter", emoji: "โฏ๏ธ", color: "#000000" }, - { level: 196, name: "Avatar of Mortis", emoji: "๐๏ธ", color: "#f8fafc" }, - { level: 197, name: "Bendu's Wisdom", emoji: "๐", color: "#78350f" }, - { level: 198, name: "The Father", emoji: "โ๏ธ", color: "#fbbf24" }, - { level: 199, name: "The Whills", emoji: "๐๏ธ", color: "#5eead4" }, - { level: 200, name: "One With The Force", emoji: "๐", color: "#ffffff" } + // 0-10: Original Ranks + { level: 0, name: "Newbie", emoji: "๐ฃ", color: "#94a3b8" }, + { level: 1, name: "Script Kid", emoji: "๐น", color: "#10b981" }, + { level: 2, name: "Code Breaker", emoji: "๐ต๏ธโโ๏ธ", color: "#f59e0b" }, + { level: 3, name: "Void Walker", emoji: "๐", color: "#6366f1" }, + { level: 4, name: "Bug Hunter", emoji: "๐", color: "#84cc16" }, + { level: 5, name: "Data Miner", emoji: "๐", color: "#06b6d4" }, + { level: 6, name: "Sys Admin", emoji: "๐ ๏ธ", color: "#ec4899" }, + { level: 7, name: "Terminal Pro", emoji: "โจ๏ธ", color: "#7c3aed" }, + { level: 8, name: "Cloud Expert", emoji: "โ๏ธ", color: "#3b82f6" }, + { level: 9, name: "Full Stack", emoji: "๐ฅ", color: "#f97316" }, + { level: 10, name: "Architect", emoji: "๐", color: "#ef4444" }, + + // 11-30: Magic the Gathering (Creatures & Keywords) + { level: 11, name: "Llanowar Elf", emoji: "๐น", color: "#2d5a27" }, + { level: 12, name: "Scryer", emoji: "๐ฎ", color: "#1d4ed8" }, + { level: 13, name: "Trampler", emoji: "๐", color: "#15803d" }, + { level: 14, name: "Flying Menace", emoji: "๐ฆ", color: "#4a044e" }, + { level: 15, name: "Mana Leech", emoji: "๐ง", color: "#0ea5e9" }, + { level: 16, name: "Spellcounter", emoji: "๐ซ", color: "#2563eb" }, + { level: 17, name: "Goblin Guide", emoji: "๐บ", color: "#dc2626" }, + { level: 18, name: "Serum Visionary", emoji: "๐งช", color: "#6366f1" }, + { level: 19, name: "Mythic Rare", emoji: "๐ ", color: "#f97316" }, + { level: 20, name: "Planeswalker", emoji: "โจ", color: "#fbbf24" }, + + // 21-40: Game of Thrones (Houses & Heroes) + { level: 21, name: "Night's Watch", emoji: "๐ฆ ", color: "#1e293b" }, + { level: 22, name: "Wildling Scout", emoji: "โ๏ธ", color: "#94a3b8" }, + { level: 23, name: "Ironborn", emoji: "โ", color: "#475569" }, + { level: 24, name: "Dothraki Rider", emoji: "๐", color: "#b45309" }, + { level: 25, name: "Kingslayer", emoji: "๐ก๏ธ", color: "#facc15" }, + { level: 26, name: "Winterfell Warden", emoji: "๐บ", color: "#cbd5e1" }, + { level: 27, name: "Dragonstone Guard", emoji: "๐", color: "#991b1b" }, + { level: 28, name: "Faceless Man", emoji: "๐ญ", color: "#4b5563" }, + { level: 29, name: "Hand of the King", emoji: "๐๏ธ", color: "#d97706" }, + { level: 30, name: "Iron Throne Heir", emoji: "โ๏ธ", color: "#111827" }, + + // 31-50: Wheel of Time (The Tiers of Power) + { level: 31, name: "Two Rivers Archer", emoji: "๐น", color: "#166534" }, + { level: 32, name: "Gleeman", emoji: "๐ถ", color: "#be185d" }, + { level: 33, name: "Borderlander", emoji: "๐ก๏ธ", color: "#991b1b" }, + { level: 34, name: "Warders Bond", emoji: "๐", color: "#1e293b" }, + { level: 35, name: "Aes Sedai Novice", emoji: "๐ฏ๏ธ", color: "#f8fafc" }, + { level: 36, name: "Accepted", emoji: "๐", color: "#e2e8f0" }, + { level: 37, name: "Aiel Dreamwalker", emoji: "๐๏ธ", color: "#d97706" }, + { level: 38, name: "Asha'man", emoji: "โก", color: "#000000" }, + { level: 39, name: "Amyrlin Seat", emoji: "๐", color: "#ffffff" }, + { level: 40, name: "Ta'veren", emoji: "๐", color: "#6366f1" }, + + // 41-60: Lord of the Rings (Fellowship & Foes) + { level: 41, name: "Hobbit Adventurer", emoji: "๐บ", color: "#15803d" }, + { level: 42, name: "Bree Strider", emoji: "๐ข", color: "#451a03" }, + { level: 43, name: "Riddermark Lord", emoji: "๐", color: "#166534" }, + { level: 44, name: "Gondor Soldier", emoji: "๐ก๏ธ", color: "#94a3b8" }, + { level: 45, name: "Uruk-hai Berserker", emoji: "โ", color: "#450a0a" }, + { level: 46, name: "Elven Archer", emoji: "๐", color: "#4ade80" }, + { level: 47, name: "Dwarf Warrior", emoji: "โ๏ธ", color: "#78350f" }, + { level: 48, name: "Nazgรปl Rider", emoji: "๐", color: "#020617" }, + { level: 49, name: "Istari Pupil", emoji: "๐ง", color: "#3b82f6" }, + { level: 50, name: "Ring-bearer", emoji: "๐", color: "#fbbf24" }, + + // NEW LEVELS 51-60 + { level: 51, name: "White Wizard", emoji: "๐งโโ๏ธ", color: "#f8fafc" }, + { level: 52, name: "Silmaril Seeker", emoji: "๐", color: "#7dd3fc" }, + { level: 53, name: "Dune Walker", emoji: "โณ", color: "#fcd34d" }, + { level: 54, name: "Shadowfax Rider", emoji: "๐", color: "#e2e8f0" }, + { level: 55, name: "Master of Coin", emoji: "๐ช", color: "#fbbf24" }, + { level: 56, name: "Kingsguard", emoji: "๐ก๏ธ", color: "#94a3b8" }, + { level: 57, name: "Valyrian Smith", emoji: "โ๏ธ", color: "#475569" }, + { level: 58, name: "Night Watcher", emoji: "๐ฆ", color: "#312e81" }, + { level: 59, name: "Obsidian Blade", emoji: "๐ก๏ธ", color: "#1e293b" }, + { level: 60, name: "Citadel Maester", emoji: "๐", color: "#8b5e3c" }, + + // 61-80: High Magic & Artifacts + { level: 61, name: "Mox Emerald", emoji: "๐", color: "#10b981" }, + { level: 62, name: "Mox Sapphire", emoji: "๐", color: "#3b82f6" }, + { level: 63, name: "Mox Ruby", emoji: "โค๏ธ", color: "#ef4444" }, + { level: 64, name: "Mox Jet", emoji: "๐ค", color: "#18181b" }, + { level: 65, name: "Mox Pearl", emoji: "๐ค", color: "#f8fafc" }, + { level: 66, name: "Black Lotus", emoji: "๐บ", color: "#000000" }, + { level: 67, name: "Balrog Slayer", emoji: "๐ฅ", color: "#f97316" }, + { level: 68, name: "Witch-king", emoji: "๐", color: "#334155" }, + { level: 69, name: "Shelob's Kin", emoji: "๐ท๏ธ", color: "#0f172a" }, + { level: 70, name: "Dragon-friend", emoji: "๐ฒ", color: "#dc2626" }, + + // NEW LEVELS 71-80 + { level: 71, name: "Neon Ghost", emoji: "๐ป", color: "#22d3ee" }, + { level: 72, name: "Dragon's Greed", emoji: "๐ช", color: "#fbbf24" }, + { level: 73, name: "Mistborn", emoji: "๐ซ๏ธ", color: "#94a3b8" }, + { level: 74, name: "Cinder Soul", emoji: "๐ฅ", color: "#f87171" }, + { level: 75, name: "High Council", emoji: "๐๏ธ", color: "#6366f1" }, + { level: 76, name: "Valyrian Steel", emoji: "๐ก๏ธ", color: "#cbd5e1" }, + { level: 77, name: "Golden Snitch", emoji: "โจ", color: "#facc15" }, + { level: 78, name: "Ether Weaver", emoji: "๐ธ๏ธ", color: "#a855f7" }, + { level: 79, name: "Star Forge", emoji: "๐จ", color: "#38bdf8" }, + { level: 80, name: "Mithril Guard", emoji: "๐ก๏ธ", color: "#e2e8f0" }, + + // 81-90: Wheel of Time (The Forsaken & Dragons) + { level: 81, name: "Lan Mandragoran", emoji: "๐ก๏ธ", color: "#1e293b" }, + { level: 82, name: "Moiraine Damodred", emoji: "๐ง", color: "#1d4ed8" }, + { level: 83, name: "Ishamael", emoji: "๐๏ธ", color: "#450a0a" }, + { level: 84, name: "Callandor Wielder", emoji: "๐", color: "#22d3ee" }, + { level: 85, name: "Lewes Therin", emoji: "โ๏ธ", color: "#fde047" }, + { level: 86, name: "Dragon Reborn", emoji: "๐", color: "#ef4444" }, + + // NEW LEVELS 87-90 + { level: 87, name: "Phoenix Down", emoji: "๐ชถ", color: "#fb7185" }, + { level: 88, name: "Void Sentinel", emoji: "๐๏ธโ๐จ๏ธ", color: "#4ade80" }, + { level: 89, name: "Elder Wand", emoji: "๐ช", color: "#94a3b8" }, + { level: 90, name: "Balrog's Whip", emoji: "๐ฅ", color: "#b91c1c" }, + + // 91-100: Cosmic Legends + { level: 91, name: "Sauron's Shadow", emoji: "๐๏ธ", color: "#000000" }, + { level: 92, name: "Galadriel's Light", emoji: "๐", color: "#e2e8f0" }, + { level: 93, name: "Eldrazi Titan", emoji: "๐", color: "#a855f7" }, + { level: 94, name: "Tom Bombadil", emoji: "๐", color: "#fbbf24" }, + { level: 95, name: "Sauron Unleashed", emoji: "๐", color: "#7f1d1d" }, + { level: 96, name: "Saruman the White", emoji: "โ", color: "#cbd5e1" }, + { level: 97, name: "Gandalf the Grey", emoji: "๐", color: "#64748b" }, + { level: 98, name: "Gandalf the White", emoji: "๐งโโ๏ธ", color: "#ffffff" }, + { level: 99, name: "The Creator", emoji: "๐", color: "#6366f1" }, + { level: 100, name: "Eru Ilรบvatar", emoji: "โจ", color: "#ffffff" }, + + { level: 101, name: "Padawan Learner", emoji: "๐ง", color: "#60a5fa" }, + { level: 102, name: "Moisture Farmer", emoji: "๐", color: "#d97706" }, + { level: 103, name: "Scrappy Scavenger", emoji: "๐ง", color: "#fcd34d" }, + { level: 104, name: "Cantina Regular", emoji: "๐น", color: "#9333ea" }, + { level: 105, name: "Holocron Finder", emoji: "๐ง", color: "#38bdf8" }, + { level: 106, name: "Speeder Racer", emoji: "๐๏ธ", color: "#fb923c" }, + { level: 107, name: "Droid Mechanic", emoji: "๐ค", color: "#94a3b8" }, + { level: 108, name: "Kyber Seeker", emoji: "๐", color: "#ffffff" }, + { level: 109, name: "Outer Rim Nomad", emoji: "๐๏ธ", color: "#a8a29e" }, + { level: 110, name: "Rebel Pilot", emoji: "๐", color: "#ef4444" }, + { level: 111, name: "Squadron Leader", emoji: "๐ก", color: "#f87171" }, + { level: 112, name: "Astromech Specialist", emoji: "๐", color: "#3b82f6" }, + { level: 113, name: "Smuggler Associate", emoji: "๐ฆ", color: "#b45309" }, + { level: 114, name: "Sabacc Champion", emoji: "๐", color: "#fbbf24" }, + { level: 115, name: "Jedi Knight", emoji: "โ๏ธ", color: "#60a5fa" }, + { level: 116, name: "Lightsaber Smith", emoji: "๐ ๏ธ", color: "#2dd4bf" }, + { level: 117, name: "Force Sensitive", emoji: "๐", color: "#818cf8" }, + { level: 118, name: "Temple Guardian", emoji: "๐ฐ", color: "#facc15" }, + { level: 119, name: "Wayseeker", emoji: "๐งญ", color: "#94a3b8" }, + { level: 120, name: "Mandalorian Initiate", emoji: "๐ก๏ธ", color: "#64748b" }, + { level: 121, name: "Foundling", emoji: "๐ถ", color: "#cbd5e1" }, + { level: 122, name: "Beskar Bearer", emoji: "๐", color: "#475569" }, + { level: 123, name: "Clan Defender", emoji: "โ๏ธ", color: "#1e293b" }, + { level: 124, name: "Jetpack Ace", emoji: "๐ฅ", color: "#f97316" }, + { level: 125, name: "Jedi Guardian", emoji: "๐ก๏ธ", color: "#22c55e" }, + + // --- IMPERIAL MIGHT: THE SHADOW (126-150) --- + { level: 126, name: "Stormtrooper Recruit", emoji: "โช", color: "#ffffff" }, + { level: 127, name: "Scout Trooper", emoji: "๐๏ธ", color: "#e2e8f0" }, + { level: 128, name: "TIE Pilot", emoji: "๐ฆ", color: "#1f2937" }, + { level: 129, name: "Imperial Officer", emoji: "๐", color: "#334155" }, + { level: 130, name: "Millennium Captain", emoji: "๐", color: "#fbbf24" }, + { level: 131, name: "Sith Acolyte", emoji: "๐", color: "#991b1b" }, + { level: 132, name: "Shadow Guard", emoji: "๐ค", color: "#000000" }, + { level: 133, name: "Inquisitor Trainee", emoji: "๐ด", color: "#dc2626" }, + { level: 134, name: "Purge Trooper", emoji: "๐งจ", color: "#450a0a" }, + { level: 135, name: "Sith Stalker", emoji: "๐ต๏ธ", color: "#7f1d1d" }, + { level: 136, name: "Red Guard", emoji: "๐ก๏ธ", color: "#b91c1c" }, + { level: 137, name: "Dark Side Adept", emoji: "๐", color: "#450606" }, + { level: 138, name: "Sith Alchemist", emoji: "๐งช", color: "#6d28d9" }, + { level: 139, name: "Holocron Corruptor", emoji: "๐ป", color: "#be123c" }, + { level: 140, name: "Imperial Inquisitor", emoji: "๐คบ", color: "#991b1b" }, + { level: 141, name: "Grand Inquisitor", emoji: "๐น", color: "#7f1d1d" }, + { + level: 142, + name: "Star Destroyer Commander", + emoji: "๐ข", + color: "#94a3b8", + }, + { + level: 143, + name: "Super Star Destroyer Admin", + emoji: "๐", + color: "#64748b", + }, + { + level: 144, + name: "Kyber Crystal Corruptor", + emoji: "๐ฉธ", + color: "#f43f5e", + }, + { level: 145, name: "Death Star Architect", emoji: "๐ฐ๏ธ", color: "#475569" }, + { level: 146, name: "Planetary Governor", emoji: "๐ช", color: "#ca8a04" }, + { level: 147, name: "Imperial Advisor", emoji: "๐ง ", color: "#a855f7" }, + { level: 148, name: "Sith Warrior", emoji: "โ๏ธ", color: "#991b1b" }, + { level: 149, name: "Dark Disciple", emoji: "๐ฅ", color: "#dc2626" }, + { level: 150, name: "Sith Lord", emoji: "๐", color: "#000000" }, + + // --- BOUNTY HUNTERS & MERCENARIES (151-175) --- + { level: 151, name: "Guild Member", emoji: "๐", color: "#8b5e3c" }, + { level: 152, name: "Tracker", emoji: "๐ฃ", color: "#a8a29e" }, + { level: 153, name: "Sniper Specialist", emoji: "๐ฏ", color: "#ef4444" }, + { + level: 154, + name: "Thermal Detonator Expert", + emoji: "๐ฃ", + color: "#f97316", + }, + { level: 155, name: "Bounty Hunter Prime", emoji: "๐๏ธ", color: "#4ade80" }, + { level: 156, name: "Carbonite Freezer", emoji: "๐ง", color: "#bae6fd" }, + { level: 157, name: "Underworld Kingpin", emoji: "๐", color: "#7c3aed" }, + { level: 158, name: "Hutt Enforcer", emoji: "๐", color: "#65a30d" }, + { level: 159, name: "Crime Syndicate Boss", emoji: "๐ผ", color: "#1e1b4b" }, + { level: 160, name: "Grand Moff", emoji: "๐ ", color: "#334155" }, + { level: 161, name: "Imperial Regent", emoji: "๐๏ธ", color: "#94a3b8" }, + { level: 162, name: "Hand of Justice", emoji: "โ๏ธ", color: "#facc15" }, + { level: 163, name: "Ancient Archivist", emoji: "๐", color: "#d97706" }, + { level: 164, name: "Dathomir Witch", emoji: "๐ฎ", color: "#db2777" }, + { level: 165, name: "Grey Jedi", emoji: "โฏ๏ธ", color: "#64748b" }, + { level: 166, name: "Balance Seeker", emoji: "๐", color: "#94a3b8" }, + { level: 167, name: "Jedi Master", emoji: "๐ง", color: "#60a5fa" }, + { level: 168, name: "Council Member", emoji: "๐ช", color: "#3b82f6" }, + { level: 169, name: "Temple Overseer", emoji: "๐๏ธ", color: "#2563eb" }, + { level: 170, name: "Jedi Sage", emoji: "๐", color: "#93c5fd" }, + { level: 171, name: "High Republic Hero", emoji: "๐", color: "#fbbf24" }, + { level: 172, name: "Living Force Vessel", emoji: "๐", color: "#4ade80" }, + { level: 173, name: "Chosen One Initiate", emoji: "โก", color: "#ffffff" }, + { level: 174, name: "Master of the Order", emoji: "๐", color: "#1d4ed8" }, + { level: 175, name: "Jedi Grand Master", emoji: "๐งโโ๏ธ", color: "#10b981" }, + + // --- THE FORCE SUPREME (176-200) --- + { level: 176, name: "Dark Side Entity", emoji: "๐", color: "#111827" }, + { level: 177, name: "Life Force Leecher", emoji: "๐ฉธ", color: "#7f1d1d" }, + { level: 178, name: "Sith Emperor", emoji: "๐", color: "#000000" }, + { level: 179, name: "World Eater", emoji: "๐", color: "#4c0519" }, + { level: 180, name: "Darth Vader's Wrath", emoji: "๐บ", color: "#b91c1c" }, + { level: 181, name: "Unstoppable Force", emoji: "๐ช๏ธ", color: "#ffffff" }, + { level: 182, name: "Immovable Object", emoji: "๐ฟ", color: "#475569" }, + { level: 183, name: "Force Projection", emoji: "โจ", color: "#7dd3fc" }, + { level: 184, name: "Voice of the Force", emoji: "๐ฃ๏ธ", color: "#e2e8f0" }, + { level: 185, name: "Emperor's Hand", emoji: "โก", color: "#a855f7" }, + { level: 186, name: "Force Stormbringer", emoji: "๐ฉ๏ธ", color: "#38bdf8" }, + { level: 187, name: "Space-Time Weaver", emoji: "๐ธ๏ธ", color: "#c084fc" }, + { + level: 188, + name: "World Between Worlds Explorer", + emoji: "๐", + color: "#a5b4fc", + }, + { level: 189, name: "Cosmic Sentinel", emoji: "๐๏ธ", color: "#2dd4bf" }, + { level: 190, name: "Force Ghost", emoji: "๐ป", color: "#bae6fd" }, + { level: 191, name: "Ethereal Guide", emoji: "๐ฏ๏ธ", color: "#ffffff" }, + { level: 192, name: "Midi-chlorian Master", emoji: "๐งฌ", color: "#4ade80" }, + { level: 193, name: "Force Nexus", emoji: "๐", color: "#facc15" }, + { level: 194, name: "Ancient One", emoji: "โณ", color: "#d97706" }, + { level: 195, name: "The Son & The Daughter", emoji: "โฏ๏ธ", color: "#000000" }, + { level: 196, name: "Avatar of Mortis", emoji: "๐๏ธ", color: "#f8fafc" }, + { level: 197, name: "Bendu's Wisdom", emoji: "๐", color: "#78350f" }, + { level: 198, name: "The Father", emoji: "โ๏ธ", color: "#fbbf24" }, + { level: 199, name: "The Whills", emoji: "๐๏ธ", color: "#5eead4" }, + { level: 200, name: "One With The Force", emoji: "๐", color: "#ffffff" }, ]; const XP_PER_LEVEL = 45; // Load saved level or start at 0 -let currentLevel = Number(localStorage.getItem('userLevel')) || 0; +let currentLevel = Number(localStorage.getItem("userLevel")) || 0; // Load saved XP or start at 0 -let currentXP = parseInt(localStorage.getItem('userXP')) || 0; - -function getContrastYIQ(hexcolor){ - hexcolor = hexcolor.replace("#", ""); - var r = parseInt(hexcolor.substr(0,2),16); - var g = parseInt(hexcolor.substr(2,2),16); - var b = parseInt(hexcolor.substr(4,2),16); - var yiq = ((r*299)+(g*587)+(b*114))/1000; - return (yiq >= 128) ? 'black' : 'white'; +let currentXP = parseInt(localStorage.getItem("userXP")) || 0; + +function getContrastYIQ(hexcolor) { + hexcolor = hexcolor.replace("#", ""); + var r = parseInt(hexcolor.substr(0, 2), 16); + var g = parseInt(hexcolor.substr(2, 2), 16); + var b = parseInt(hexcolor.substr(4, 2), 16); + var yiq = (r * 299 + g * 587 + b * 114) / 1000; + return yiq >= 128 ? "black" : "white"; } - function isEggUnlocked(eggId) { - // Returns true if the ID exists in the array, false otherwise - return unlockedEggs.includes(eggId); + // Returns true if the ID exists in the array, false otherwise + return unlockedEggs.includes(eggId); } /** @@ -263,491 +286,522 @@ function isEggUnlocked(eggId) { let audioCtx; function initAudio() { - try { - if (!audioCtx) { - audioCtx = new (window.AudioContext || window.webkitAudioContext)(); - } - if (audioCtx.state === 'suspended') { - audioCtx.resume(); - } - } catch (e) { - console.error("AudioContext failed to initialize:", e); + try { + if (!audioCtx) { + audioCtx = new (window.AudioContext || window.webkitAudioContext)(); } + if (audioCtx.state === "suspended") { + audioCtx.resume(); + } + } catch (e) { + console.error("AudioContext failed to initialize:", e); + } } -window.addEventListener('click', initAudio, { once: true }); -window.addEventListener('keydown', initAudio, { once: true }); +window.addEventListener("click", initAudio, { once: true }); +window.addEventListener("keydown", initAudio, { once: true }); function playSound(type) { - initAudio(); - if (!audioCtx || audioCtx.state !== 'running') return; - - const osc = audioCtx.createOscillator(); - const gain = audioCtx.createGain(); - osc.connect(gain); - gain.connect(audioCtx.destination); - const now = audioCtx.currentTime; - - if (type === 'click') { - osc.type = 'sine'; - osc.frequency.setValueAtTime(880, now); - gain.gain.setValueAtTime(0.1, now); - gain.gain.exponentialRampToValueAtTime(0.01, now + 0.1); - osc.start(now); - osc.stop(now + 0.1); - } - else if (type === 'levelUp') { - osc.type = 'square'; - osc.frequency.setValueAtTime(440, now); - osc.frequency.exponentialRampToValueAtTime(880, now + 0.4); - gain.gain.setValueAtTime(0.15, now); - gain.gain.exponentialRampToValueAtTime(0.01, now + 1.0); - osc.start(now); - osc.stop(now + 1.5); - } - else if (type === 'secret') { - osc.type = 'triangle'; - [523.25, 659.25, 783.99, 1046.50].forEach((freq, i) => { - const s = audioCtx.createOscillator(); - const g = audioCtx.createGain(); - s.connect(g); g.connect(audioCtx.destination); - s.frequency.setValueAtTime(freq, now + i * 0.3); - g.gain.setValueAtTime(0.07, now + i * 0.3); - g.gain.exponentialRampToValueAtTime(0.01, now + i * 0.3 + 0.3); - s.start(now + i * 0.3); - s.stop(now + i * 0.3 + 0.3); - }); - } - else if (type === 'restore') { - osc.type = 'sine'; - [220, 440, 880, 1760].forEach((freq, i) => { - const s = audioCtx.createOscillator(); - const g = audioCtx.createGain(); - s.connect(g); g.connect(audioCtx.destination); - s.frequency.setValueAtTime(freq, now + i * 0.05); - g.gain.setValueAtTime(0.1, now + i * 0.05); - g.gain.exponentialRampToValueAtTime(0.01, now + i * 0.05 + 0.1); - s.start(now + i * 0.05); - s.stop(now + i * 0.05 + 0.1); - }); - } + initAudio(); + if (!audioCtx || audioCtx.state !== "running") return; + + const osc = audioCtx.createOscillator(); + const gain = audioCtx.createGain(); + osc.connect(gain); + gain.connect(audioCtx.destination); + const now = audioCtx.currentTime; + + if (type === "click") { + osc.type = "sine"; + osc.frequency.setValueAtTime(880, now); + gain.gain.setValueAtTime(0.1, now); + gain.gain.exponentialRampToValueAtTime(0.01, now + 0.1); + osc.start(now); + osc.stop(now + 0.1); + } else if (type === "levelUp") { + osc.type = "square"; + osc.frequency.setValueAtTime(440, now); + osc.frequency.exponentialRampToValueAtTime(880, now + 0.4); + gain.gain.setValueAtTime(0.15, now); + gain.gain.exponentialRampToValueAtTime(0.01, now + 1.0); + osc.start(now); + osc.stop(now + 1.5); + } else if (type === "secret") { + osc.type = "triangle"; + [523.25, 659.25, 783.99, 1046.5].forEach((freq, i) => { + const s = audioCtx.createOscillator(); + const g = audioCtx.createGain(); + s.connect(g); + g.connect(audioCtx.destination); + s.frequency.setValueAtTime(freq, now + i * 0.3); + g.gain.setValueAtTime(0.07, now + i * 0.3); + g.gain.exponentialRampToValueAtTime(0.01, now + i * 0.3 + 0.3); + s.start(now + i * 0.3); + s.stop(now + i * 0.3 + 0.3); + }); + } else if (type === "restore") { + osc.type = "sine"; + [220, 440, 880, 1760].forEach((freq, i) => { + const s = audioCtx.createOscillator(); + const g = audioCtx.createGain(); + s.connect(g); + g.connect(audioCtx.destination); + s.frequency.setValueAtTime(freq, now + i * 0.05); + g.gain.setValueAtTime(0.1, now + i * 0.05); + g.gain.exponentialRampToValueAtTime(0.01, now + i * 0.05 + 0.1); + s.start(now + i * 0.05); + s.stop(now + i * 0.05 + 0.1); + }); + } } - -let unlockedEggs = JSON.parse(localStorage.getItem('unlockedEggs')) || []; +let unlockedEggs = JSON.parse(localStorage.getItem("unlockedEggs")) || []; let surpriseClickCount = 0; let matrixActive = false; let destructInterval; function getRank(lvl) { - const numericLevel = Number(lvl) || 0; + const numericLevel = Number(lvl) || 0; - // IMPORTANT: .slice().reverse() creates a temporary reversed list - // so we find the HIGHEST level match first. - const rank = LEVELS.slice().reverse().find(r => numericLevel >= r.level); + // IMPORTANT: .slice().reverse() creates a temporary reversed list + // so we find the HIGHEST level match first. + const rank = LEVELS.slice() + .reverse() + .find((r) => numericLevel >= r.level); - if (!rank) { - console.warn("Rank not found, defaulting to Newbie"); - return LEVELS[0]; - } + if (!rank) { + console.warn("Rank not found, defaulting to Newbie"); + return LEVELS[0]; + } - return rank; + return rank; } +const consoleContainer = document.getElementById("matrix-console-container"); +const consoleOutput = document.getElementById("matrix-console-output"); -const consoleContainer = document.getElementById('matrix-console-container'); -const consoleOutput = document.getElementById('matrix-console-output'); - -const dragContainer = document.getElementById('matrix-console-container'); -const dragHeader = dragContainer.querySelector('.bg-green-500\\/10'); // Selects the header bar +const dragContainer = document.getElementById("matrix-console-container"); +const dragHeader = dragContainer.querySelector(".bg-green-500\\/10"); // Selects the header bar let isDragging = false; let offsetLeft = 0; let offsetTop = 0; -dragHeader.addEventListener('mousedown', (e) => { - // Prevent dragging when clicking the minimize/close buttons - if (e.target.tagName === 'BUTTON') return; +dragHeader.addEventListener("mousedown", (e) => { + // Prevent dragging when clicking the minimize/close buttons + if (e.target.tagName === "BUTTON") return; - isDragging = true; + isDragging = true; - // Calculate where the mouse is relative to the top-left of the console - const rect = dragContainer.getBoundingClientRect(); - offsetLeft = e.clientX - rect.left; - offsetTop = e.clientY - rect.top; + // Calculate where the mouse is relative to the top-left of the console + const rect = dragContainer.getBoundingClientRect(); + offsetLeft = e.clientX - rect.left; + offsetTop = e.clientY - rect.top; - // Change cursor to indicate moving - dragHeader.style.cursor = 'grabbing'; + // Change cursor to indicate moving + dragHeader.style.cursor = "grabbing"; }); -document.addEventListener('mousemove', (e) => { - if (!isDragging) return; +document.addEventListener("mousemove", (e) => { + if (!isDragging) return; - // Calculate new position - let x = e.clientX - offsetLeft; - let y = e.clientY - offsetTop; + // Calculate new position + let x = e.clientX - offsetLeft; + let y = e.clientY - offsetTop; - // Boundary Check (Optional: keeps it inside the screen) - x = Math.max(0, Math.min(x, window.innerWidth - dragContainer.offsetWidth)); - y = Math.max(0, Math.min(y, window.innerHeight - dragContainer.offsetHeight)); + // Boundary Check (Optional: keeps it inside the screen) + x = Math.max(0, Math.min(x, window.innerWidth - dragContainer.offsetWidth)); + y = Math.max(0, Math.min(y, window.innerHeight - dragContainer.offsetHeight)); - // Apply position and remove Tailwind's 'bottom' and 'right' so they don't fight the 'top'/'left' - dragContainer.style.bottom = 'auto'; - dragContainer.style.right = 'auto'; - dragContainer.style.left = `${x}px`; - dragContainer.style.top = `${y}px`; + // Apply position and remove Tailwind's 'bottom' and 'right' so they don't fight the 'top'/'left' + dragContainer.style.bottom = "auto"; + dragContainer.style.right = "auto"; + dragContainer.style.left = `${x}px`; + dragContainer.style.top = `${y}px`; }); -document.addEventListener('mouseup', () => { - isDragging = false; - dragHeader.style.cursor = 'grab'; +document.addEventListener("mouseup", () => { + isDragging = false; + dragHeader.style.cursor = "grab"; }); function minimizeConsole() { - // Toggles the height of the output area - if (consoleOutput.style.display === 'none') { - consoleOutput.style.display = 'block'; - consoleContainer.style.width = '20rem'; // w-80 - } else { - consoleOutput.style.display = 'none'; - consoleContainer.style.width = '150px'; // Compact view - } + // Toggles the height of the output area + if (consoleOutput.style.display === "none") { + consoleOutput.style.display = "block"; + consoleContainer.style.width = "20rem"; // w-80 + } else { + consoleOutput.style.display = "none"; + consoleContainer.style.width = "150px"; // Compact view + } } function maximizeConsole() { - // Toggles a full-screen-ish mode - consoleContainer.classList.toggle('console-maximized'); - - // Adjust height when maximized - if (consoleContainer.classList.contains('console-maximized')) { - consoleOutput.style.height = '70vh'; - consoleOutput.style.display = 'block'; - } else { - consoleOutput.style.height = '12rem'; // h-48 - } + // Toggles a full-screen-ish mode + consoleContainer.classList.toggle("console-maximized"); + + // Adjust height when maximized + if (consoleContainer.classList.contains("console-maximized")) { + consoleOutput.style.height = "70vh"; + consoleOutput.style.display = "block"; + } else { + consoleOutput.style.height = "12rem"; // h-48 + } } function closeConsole() { - const container = document.getElementById('matrix-console-container'); - const reopenBtn = document.getElementById('reopen-console-btn'); - - // Hide the console - container.style.opacity = '0'; - container.style.transform = 'translateY(20px)'; - - setTimeout(() => { - container.classList.add('hidden'); - // Show the small reopen button - if (reopenBtn) reopenBtn.classList.remove('hidden'); - }, 300); + const container = document.getElementById("matrix-console-container"); + const reopenBtn = document.getElementById("reopen-console-btn"); + + // Hide the console + container.style.opacity = "0"; + container.style.transform = "translateY(20px)"; + + setTimeout(() => { + container.classList.add("hidden"); + // Show the small reopen button + if (reopenBtn) reopenBtn.classList.remove("hidden"); + }, 300); } function reopenConsole() { - const container = document.getElementById('matrix-console-container'); - const reopenBtn = document.getElementById('reopen-console-btn'); + const container = document.getElementById("matrix-console-container"); + const reopenBtn = document.getElementById("reopen-console-btn"); - // Show the console - container.classList.remove('hidden'); + // Show the console + container.classList.remove("hidden"); - // Trigger reflow for animation - void container.offsetWidth; + // Trigger reflow for animation + void container.offsetWidth; - container.style.opacity = '1'; - container.style.transform = 'translateY(0)'; + container.style.opacity = "1"; + container.style.transform = "translateY(0)"; - // Hide the reopen button - if (reopenBtn) reopenBtn.classList.add('hidden'); + // Hide the reopen button + if (reopenBtn) reopenBtn.classList.add("hidden"); } - let isProcessingXP = false; // Ensure this is in the GLOBAL scope (not hidden inside another function) -window.createFloatingXP = function(e) { - // Prevent "spam" firing from high-speed mouse movement - if (isProcessingXP) return; - isProcessingXP = true; +window.createFloatingXP = function (e) { + // Prevent "spam" firing from high-speed mouse movement + if (isProcessingXP) return; + isProcessingXP = true; - // Release the lock after 50ms - setTimeout(() => { isProcessingXP = false; }, 50); + // Release the lock after 50ms + setTimeout(() => { + isProcessingXP = false; + }, 50); - // 1. Create the XP element - const popup = document.createElement('div'); + // 1. Create the XP element + const popup = document.createElement("div"); - // 2. Styling (Tailwind classes + Inline for positioning) - popup.className = 'fixed pointer-events-none z-[999] font-black text-sm tracking-tighter animate-xp-float'; - popup.innerText = '+1 XP'; + // 2. Styling (Tailwind classes + Inline for positioning) + popup.className = + "fixed pointer-events-none z-[999] font-black text-sm tracking-tighter animate-xp-float"; + popup.innerText = "+1 XP"; - // 3. Get current Rank color for the "Pop" - const rank = getRank(currentLevel); - popup.style.color = rank.color; + // 3. Get current Rank color for the "Pop" + const rank = getRank(currentLevel); + popup.style.color = rank.color; - // 4. Position at mouse (using clientX/Y for fixed positioning) - popup.style.left = `${e.clientX}px`; - popup.style.top = `${e.clientY}px`; + // 4. Position at mouse (using clientX/Y for fixed positioning) + popup.style.left = `${e.clientX}px`; + popup.style.top = `${e.clientY}px`; - document.body.appendChild(popup); + document.body.appendChild(popup); - // 5. Award XP and update that "Newbie" header - if (typeof addExperience === 'function') { - addExperience(1); - } + // 5. Award XP and update that "Newbie" header + if (typeof addExperience === "function") { + addExperience(1); + } - // 6. Cleanup - setTimeout(() => popup.remove(), 800); + // 6. Cleanup + setTimeout(() => popup.remove(), 800); }; // Re-attach listeners to your skill tags function attachSkillListeners() { - const skillTags = document.querySelectorAll('.skill-tag'); // Use your actual class name - skillTags.forEach(tag => { - // Use 'mouseenter' for a clean single-pop on hover - tag.addEventListener('mouseenter', createXPPopup); - }); + const skillTags = document.querySelectorAll(".skill-tag"); // Use your actual class name + skillTags.forEach((tag) => { + // Use 'mouseenter' for a clean single-pop on hover + tag.addEventListener("mouseenter", createXPPopup); + }); } function unlockEgg(eggId) { - if (!unlockedEggs.includes(eggId)) { - unlockedEggs.push(eggId); - localStorage.setItem('unlockedEggs', JSON.stringify(unlockedEggs)); - playSound('levelUp'); - showLevelUpNotification(unlockedEggs.length); - updateGameUI(); - } + if (!unlockedEggs.includes(eggId)) { + unlockedEggs.push(eggId); + localStorage.setItem("unlockedEggs", JSON.stringify(unlockedEggs)); + playSound("levelUp"); + showLevelUpNotification(unlockedEggs.length); + updateGameUI(); + } } function handleLevelClick() { - triggerSecretUnlock('badge_click'); + triggerSecretUnlock("badge_click"); } function showLevelUpNotification(input) { - // Determine if input is a rank object or a level number - let rank; - if (typeof input === 'object' && input !== null) { - rank = input; - } else { - rank = getRank(input); // Convert number to rank object - } + // Determine if input is a rank object or a level number + let rank; + if (typeof input === "object" && input !== null) { + rank = input; + } else { + rank = getRank(input); // Convert number to rank object + } - // Safety fallback to prevent the "undefined" crash - if (!rank) rank = LEVELS[0]; + // Safety fallback to prevent the "undefined" crash + if (!rank) rank = LEVELS[0]; - const notify = document.createElement('div'); - notify.className = "fixed top-24 left-1/2 -translate-x-1/2 z-[2000] px-8 py-4 bg-white dark:bg-slate-900 border-4 rounded-full shadow-2xl flex items-center gap-4 animate-bounce"; + const notify = document.createElement("div"); + notify.className = + "fixed top-24 left-1/2 -translate-x-1/2 z-[2000] px-8 py-4 bg-white dark:bg-slate-900 border-4 rounded-full shadow-2xl flex items-center gap-4 animate-bounce"; - // Now rank.color is guaranteed to exist - notify.style.borderColor = rank.color; + // Now rank.color is guaranteed to exist + notify.style.borderColor = rank.color; - notify.innerHTML = ` + notify.innerHTML = ` ${rank.emoji}
${rank.name}