๐ŸŽฎArcadeLab

Fortnite - Chapter 1 Season 1

by StormPanda35
561 lines16.6 KB
โ–ถ Play
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Fortnite - Chapter 1 Season 1</title>
<style>
* { box-sizing: border-box; }
body {
  margin: 0;
  color: white;
  font-family: Arial, sans-serif;
  background: #07182b;
}
button, input { font: inherit; }
button { cursor: pointer; font-weight: bold; }
button:hover { filter: brightness(1.15); }
.hidden { display: none !important; }

#authScreen {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 20px;
  background:
    radial-gradient(ellipse at 50% 20%, #246a9b, transparent 60%),
    linear-gradient(145deg, #081326, #164a70);
}
.authbox {
  width: min(430px, 100%);
  padding: 35px;
  background: #101d31ed;
  border: 2px solid #4aa8e9;
  box-shadow: 0 0 35px #0008;
  text-align: center;
}
.logo { font-size: 36px; font-weight: 1000; font-style: italic; }
.logo span { color: #f8d94e; }
.auth-sub { color: #82d1ff; margin: 8px 0 28px; }
label { display: block; text-align: left; margin-bottom: 8px; font-size: 12px; }
input {
  width: 100%;
  padding: 13px;
  border: 1px solid #66819d;
  background: #071426;
  color: white;
  margin-bottom: 14px;
}
.primary {
  background: #f3c62f;
  border: 0;
  padding: 14px;
  color: #14233b;
  width: 100%;
}
#authMessage { color: #ffaaaa; min-height: 25px; margin-top: 12px; }
.fineprint { color: #9daec2; font-size: 11px; line-height: 1.5; }

#game {
  min-height: 100vh;
  background:
    linear-gradient(90deg, #071629e8, #0b2946aa),
    radial-gradient(ellipse at 75% 45%, #2784a3, #123f61 45%, #08162a);
}
header {
  height: 75px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 4%;
  background: #081321e8;
  border-bottom: 2px solid #e3bb37;
  gap: 15px;
}
.brand { font-size: 25px; font-weight: 1000; font-style: italic; }
.brand span { color: #f4cb37; }
.header-right { display: flex; align-items: center; gap: 15px; }
.small-button { background: #233c57; color: white; border: 1px solid #617b95; padding: 9px 12px; }
nav {
  display: flex;
  gap: 8px;
  padding: 14px 4%;
  background: #101f33;
  flex-wrap: wrap;
}
nav button {
  border: 0;
  padding: 12px 20px;
  color: white;
  background: transparent;
}
nav button.active { background: #e9c13c; color: #10233b; }
.page { display: none; padding: 25px 4%; }
.page.active { display: block; }
.lobby-layout {
  min-height: 490px;
  display: grid;
  grid-template-columns: minmax(250px, 1fr) minmax(260px, 1.2fr);
  gap: 25px;
}
.panel {
  background: #09172ad9;
  border: 1px solid #42617c;
  padding: 22px;
}
h1 { margin-top: 0; font-size: 30px; }
h2 { font-size: 20px; }
.muted { color: #a9bed1; }
.mode-row { display: flex; gap: 10px; margin: 20px 0; }
.mode {
  flex: 1;
  padding: 16px 8px;
  background: #172c43;
  border: 2px solid #3d5c77;
  color: white;
}
.mode.selected { border-color: #f1ce40; background: #294563; }
#play {
  width: 100%;
  padding: 17px;
  border: 0;
  color: #142238;
  background: #f4cc38;
  font-size: 19px;
}
#unready {
  width: 100%;
  padding: 14px;
  margin-top: 10px;
  border: 1px solid #8095a8;
  background: #273d55;
  color: white;
}
#status { margin-top: 15px; color: #9fddff; min-height: 22px; }
.player-stage {
  display: grid;
  place-items: center;
  position: relative;
  overflow: hidden;
  min-height: 400px;
  background: radial-gradient(ellipse at 50% 65%, #3e9dc0, #154768 45%, #0b1a2e);
}
.player-stage:after {
  content: "";
  position: absolute;
  bottom: 35px;
  width: 220px;
  height: 25px;
  background: #020a15;
  border-radius: 50%;
  filter: blur(9px);
}
.figure {
  position: relative;
  z-index: 1;
  width: 125px;
  height: 260px;
  margin-top: 30px;
}
.head {
  position: absolute;
  top: 0;
  left: 40px;
  width: 48px;
  height: 52px;
  border: 3px solid #1b2636;
  border-radius: 10px;
  background: #d7a77c;
}
.hair {
  position: absolute;
  top: -5px;
  left: 37px;
  width: 54px;
  height: 20px;
  border-radius: 12px 12px 3px 3px;
  background: #3a2a22;
}
.torso {
  position: absolute;
  top: 52px;
  left: 24px;
  width: 80px;
  height: 105px;
  border: 3px solid #1b2636;
  border-radius: 12px 12px 5px 5px;
  background: #2478c6;
}
.arm {
  position: absolute;
  top: 59px;
  width: 23px;
  height: 90px;
  border: 3px solid #1b2636;
  border-radius: 9px;
  background: #d7a77c;
}
.arm.left { left: 3px; transform: rotate(8deg); }
.arm.right { right: 3px; transform: rotate(-8deg); }
.leg {
  position: absolute;
  top: 151px;
  width: 36px;
  height: 94px;
  border: 3px solid #1b2636;
  border-radius: 4px 4px 10px 10px;
  background: #253e62;
}
.leg.left { left: 27px; }
.leg.right { right: 27px; }
.figure.clowner .head { background: white; }
.figure.clowner .hair { background: #e73d45; height: 28px; }
.figure.clowner .torso {
  background: repeating-linear-gradient(45deg, #e13c4b 0 12px, #f6f0d9 12px 24px);
}
.figure.clowner .arm { background: #f5f0db; }
.figure.clowner .leg { background: #b52b43; }
.skin-label {
  position: absolute;
  z-index: 2;
  bottom: 12px;
  font-weight: bold;
  letter-spacing: 2px;
}
.skin-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 15px;
}
.skin-card {
  background: #10243a;
  border: 2px solid #45617b;
  padding: 15px;
  text-align: center;
}
.skin-card.selected { border-color: #f4d33e; }
.skin-card.locked { opacity: .65; }
.skin-card .figure { transform: scale(.7); transform-origin: top center; margin-bottom: -60px; }
.skin-card button { margin-top: 12px; padding: 10px; width: 100%; border: 0; background: #eac63a; color: #13243a; }
.badge { font-size: 11px; color: #9ec8ed; letter-spacing: 1px; }
#lockerNotice { color: #ffcc65; min-height: 25px; }
.stat { background: #142b43; padding: 20px; margin: 12px 0; }
#logout { color: white; background: #7a2932; border: 0; padding: 9px 12px; }

@media (max-width: 700px) {
  header { height: auto; padding: 15px 4%; flex-wrap: wrap; }
  .lobby-layout { grid-template-columns: 1fr; }
  .player-stage { min-height: 340px; }
  .authbox { padding: 25px; }
}
</style>
</head>
<body>

<section id="authScreen">
  <div class="authbox">
    <div class="logo">FORTNITE<span>โ˜…</span></div>
    <div class="auth-sub">CHAPTER 1 ยท SEASON 1</div>
    <form id="usernameForm">
      <label for="username">CHOOSE YOUR USERNAME</label>
      <input id="username" maxlength="20" minlength="3"
        placeholder="Enter a username" autocomplete="off" required>
      <button class="primary" type="submit">LAUNCH GAME</button>
    </form>
    <div id="authMessage" role="status"></div>
    <div class="fineprint">
      Usernames can be reused. Volxer requires a special code.
    </div>
  </div>
</section>

<div id="game" class="hidden">
  <header>
    <div class="brand">FORTNITE<span>โ˜…</span></div>
    <div class="header-right">
      <span>LEVEL <strong>1</strong></span>
      <strong id="headerUser">Player</strong>
      <button id="logout" type="button">LOG OUT</button>
    </div>
  </header>

  <nav>
    <button class="active" data-tab="lobby">PLAY</button>
    <button data-tab="locker">LOCKER</button>
    <button data-tab="shop">ITEM SHOP</button>
    <button data-tab="career">CAREER</button>
  </nav>

  <main>
    <section id="lobby" class="page active">
      <div class="lobby-layout">
        <div class="panel">
          <div class="badge">CHAPTER 1 ยท SEASON 1</div>
          <h1>BATTLE ROYALE</h1>
          <p class="muted">Drop in. Loot up. Be the last one standing.</p>

          <h2>SELECT GAME MODE</h2>
          <div class="mode-row">
            <button class="mode selected" data-mode="Solo">SOLO</button>
            <button class="mode" data-mode="Duos">DUOS</button>
          </div>
          <p id="modeDescription" class="muted">Every player for themselves.</p>

          <button id="play" type="button">PLAY</button>
          <button id="unready" type="button" class="hidden">UNREADY</button>
          <div id="status" role="status">Ready to play.</div>
        </div>

        <div class="player-stage">
          <div id="lobbyFigure" class="figure">
            <div class="hair"></div><div class="head"></div>
            <div class="arm left"></div><div class="arm right"></div>
            <div class="torso"></div>
            <div class="leg left"></div><div class="leg right"></div>
          </div>
          <div id="lobbySkinName" class="skin-label">BLUE</div>
        </div>
      </div>
    </section>

    <section id="locker" class="page">
      <div class="panel">
        <h1>LOCKER</h1>
        <p class="muted">Choose your outfit.</p>
        <p id="lockerNotice" role="status"></p>
        <div class="skin-grid">
          <div class="skin-card selected" data-skin="Blue">
            <div class="badge">COMMON OUTFIT</div>
            <div class="figure">
              <div class="hair"></div><div class="head"></div>
              <div class="arm left"></div><div class="arm right"></div>
              <div class="torso"></div>
              <div class="leg left"></div><div class="leg right"></div>
            </div>
            <h2>Blue</h2>
            <p class="muted">Classic default outfit</p>
            <button type="button" class="select-skin">EQUIP</button>
          </div>

          <div class="skin-card" data-skin="Clowner">
            <div class="badge">SPECIAL OUTFIT</div>
            <div class="figure clowner">
              <div class="hair"></div><div class="head"></div>
              <div class="arm left"></div><div class="arm right"></div>
              <div class="torso"></div>
              <div class="leg left"></div><div class="leg right"></div>
            </div>
            <h2>Clowner</h2>
            <p class="muted">Reserved for Volxer</p>
            <button type="button" class="select-skin">EQUIP</button>
          </div>
        </div>
      </div>
    </section>

    <section id="shop" class="page">
      <div class="panel">
        <h1>ITEM SHOP</h1>
        <p>Welcome to the Item Shop!</p>
        <div class="stat">
          <h2>Daily Shop</h2>
          <p class="muted">No items available in this prototype.</p>
        </div>
        <div class="stat">
          <h2>Featured Items</h2>
          <p class="muted">More outfits coming soon.</p>
        </div>
      </div>
    </section>

    <section id="career" class="page">
      <div class="panel">
        <h1>CAREER</h1>
        <div class="stat">USERNAME: <strong id="careerUser">Player</strong></div>
        <div class="stat">LEVEL: <strong>1</strong></div>
        <div class="stat">EQUIPPED OUTFIT: <strong id="careerSkin">Blue</strong></div>
        <div class="stat">SEASON: <strong>CHAPTER 1 ยท SEASON 1</strong></div>
      </div>
    </section>
  </main>
</div>

<script>
const SECRET_CODE = "notcha";

let currentUser = "";
let equippedSkin = "Blue";
let selectedMode = "Solo";
let matchmaking = false;

const authScreen = document.getElementById("authScreen");
const game = document.getElementById("game");
const usernameInput = document.getElementById("username");
const authMessage = document.getElementById("authMessage");

function isVolxer() {
  return currentUser === "Volxer";
}

function makeFigureClowner(figure, skin) {
  figure.classList.toggle("clowner", skin === "Clowner");
}

function updateSkinUI() {
  if (isVolxer()) equippedSkin = "Clowner";
  else if (equippedSkin === "Clowner") equippedSkin = "Blue";

  makeFigureClowner(document.getElementById("lobbyFigure"), equippedSkin);
  document.getElementById("lobbySkinName").textContent = equippedSkin.toUpperCase();
  document.getElementById("careerSkin").textContent = equippedSkin;

  document.querySelectorAll(".skin-card").forEach(card => {
    const skin = card.dataset.skin;
    card.classList.toggle("selected", skin === equippedSkin);

    const button = card.querySelector(".select-skin");

    if (skin === "Clowner" && !isVolxer()) {
      card.classList.add("locked");
      button.textContent = "LOCKED";
      button.disabled = true;
    } else {
      card.classList.remove("locked");
      button.disabled = false;
      button.textContent = skin === equippedSkin ? "EQUIPPED" : "EQUIP";
    }
  });
}

document.getElementById("usernameForm").addEventListener("submit", function(e) {
  e.preventDefault();

  const username = usernameInput.value.trim();

  if (!/^[A-Za-z0-9_]{3,20}$/.test(username)) {
    authMessage.textContent =
      "Use 3โ€“20 letters, numbers, or underscores.";
    return;
  }

  // Only the exact spelling "Volxer" receives the special account.
  if (username === "Volxer") {
    const code = prompt("Volxer is reserved! Enter the secret code:");

    if (code !== SECRET_CODE) {
      authMessage.textContent = "Incorrect code. Volxer is reserved!";
      return;
    }
  } else if (username.toLowerCase() === "volxer") {
    authMessage.textContent =
      "Please type Volxer with an uppercase V to use that username.";
    return;
  }

  currentUser = username;
  equippedSkin = isVolxer() ? "Clowner" : "Blue";

  document.getElementById("headerUser").textContent = currentUser;
  document.getElementById("careerUser").textContent = currentUser;

  authScreen.classList.add("hidden");
  game.classList.remove("hidden");

  document.querySelectorAll(".page").forEach(page => page.classList.remove("active"));
  document.getElementById("lobby").classList.add("active");
  document.querySelectorAll("nav button").forEach(btn => btn.classList.remove("active"));
  document.querySelector('nav button[data-tab="lobby"]').classList.add("active");

  matchmaking = false;
  document.getElementById("play").classList.remove("hidden");
  document.getElementById("unready").classList.add("hidden");
  document.getElementById("status").textContent = "Ready to play.";

  updateSkinUI();
});

document.querySelectorAll("nav button[data-tab]").forEach(button => {
  button.addEventListener("click", () => {
    const tab = button.dataset.tab;

    document.querySelectorAll("nav button").forEach(btn => btn.classList.remove("active"));
    button.classList.add("active");

    document.querySelectorAll(".page").forEach(page => page.classList.remove("active"));
    document.getElementById(tab).classList.add("active");
  });
});

document.querySelectorAll(".mode").forEach(button => {
  button.addEventListener("click", () => {
    selectedMode = button.dataset.mode;

    document.querySelectorAll(".mode").forEach(btn => {
      btn.classList.toggle("selected", btn === button);
    });

    document.getElementById("modeDescription").textContent =
      selectedMode === "Solo"
        ? "Every player for themselves."
        : "Team up with one other player.";

    if (matchmaking) {
      document.getElementById("status").textContent =
        "Mode changed to " + selectedMode + ". Press PLAY to ready up again.";
      matchmaking = false;
      document.getElementById("play").classList.remove("hidden");
      document.getElementById("unready").classList.add("hidden");
    }
  });
});

document.getElementById("play").addEventListener("click", () => {
  matchmaking = true;
  document.getElementById("play").classList.add("hidden");
  document.getElementById("unready").classList.remove("hidden");
  document.getElementById("status").textContent =
    "MATCHMAKING... Mode: " + selectedMode;
});

document.getElementById("unready").addEventListener("click", () => {
  matchmaking = false;
  document.getElementById("play").classList.remove("hidden");
  document.getElementById("unready").classList.add("hidden");
  document.getElementById("status").textContent = "You are no longer queued.";
});

document.querySelectorAll(".select-skin").forEach(button => {
  button.addEventListener("click", () => {
    const card = button.closest(".skin-card");
    const skin = card.dataset.skin;

    if (skin === "Clowner" && !isVolxer()) {
      document.getElementById("lockerNotice").textContent =
        "Clowner is reserved for Volxer!";
      return;
    }

    equippedSkin = skin;
    document.getElementById("lockerNotice").textContent =
      skin + " equipped!";

    updateSkinUI();
  });
});

document.getElementById("logout").addEventListener("click", () => {
  currentUser = "";
  equippedSkin = "Blue";
  matchmaking = false;
  usernameInput.value = "";
  authMessage.textContent = "";

  game.classList.add("hidden");
  authScreen.classList.remove("hidden");
  usernameInput.focus();
});
</script>
</body>
</html>

Game Source: Fortnite - Chapter 1 Season 1

Creator: StormPanda35

Libraries: none

Complexity: complex (561 lines, 16.6 KB)

The full source code is displayed above on this page.

Remix Instructions

To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: fortnite-chapter-1-season-1-stormpanda35" to link back to the original. Then publish at arcadelab.ai/publish.