JSFiddle - React, Tailwind, and code Playground

HTML

<div id="pinkWinkApp">
  <section id="introScreen" class="screen active intro-screen">
    <div class="intro-sparkles" aria-hidden="true"><i>✦</i><i>♥</i><i>✦</i><i>♥</i></div>
    <p class="eyebrow">WEEKLY SMALL TALKS</p>
    <div class="logo-badge"><span>♥</span></div>
    <h1>Pink Wink</h1>
    <p class="subtitle">Build Your Pink Parade!</p>
    <p class="intro-copy">Hold to win people over. Tap fast when a rival joins in. How big can your parade get in 30 seconds?</p>
    <div class="how-to">
      <div><span class="how-icon">☝</span><b>HOLD</b><small>on walkers</small></div>
      <div><span class="how-icon">⚡</span><b>TAP FAST</b><small>in a style battle</small></div>
      <div><span class="how-icon">♥</span><b>COLLECT</b><small>your pink crowd</small></div>
    </div>
    <button id="startBtn" class="main-btn">START THE PARADE</button>
  </section>

  <section id="gameScreen" class="screen game-screen">
    <header class="hud">
      <div class="hud-box"><small>TIME</small><strong id="timeValue">30</strong></div>
      <div class="hud-title">PINK WINK <span>♥</span></div>
      <div class="hud-box right"><small>SCORE</small><strong id="scoreValue">0</strong></div>
    </header>

    <div id="street" class="street">
      <div class="skyline far"></div>
      <div class="skyline near"></div>
      <div class="shop shop-one"><span>PINK CAFÉ</span></div>
      <div class="shop shop-two"><span>VINYL</span></div>
      <div class="awning"></div>
      <div class="sidewalk-lines"></div>
      <div class="street-copy">MAKE THE STREET PINK</div>

      <div id="player" class="person player">
        <div class="person-shadow"></div><div class="hair"></div><div class="head"><i></i></div>
        <div class="body"></div><div class="arm left"></div><div class="arm right"></div>
        <div class="leg left"></div><div class="leg right"></div>
        <div class="player-tag">YOU</div>
      </div>

      <div id="winkBeam"...

CSS

@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@500;700;900&family=Shrikhand&display=swap');

*{box-sizing:border-box}html,body{margin:0;min-height:100%;font-family:"DM Sans",Arial,sans-serif;background:#fff3f6;color:#5a2340}button{font:inherit}button,.walker{touch-action:manipulation;-webkit-tap-highlight-color:transparent}#pinkWinkApp{min-height:100vh;overflow:hidden;background:radial-gradient(circle at 15% 10%,#fff 0 8%,transparent 30%),linear-gradient(145deg,#fff4f7,#ffd6e3 58%,#f3a6bf)}.screen{display:none;min-height:100vh;position:relative}.screen.active{display:flex}

.intro-screen{align-items:center;justify-content:center;flex-direction:column;text-align:center;padding:38px 20px;overflow:hidden}.intro-screen:before,.intro-screen:after{content:"";position:absolute;width:420px;height:420px;border:90px solid rgba(255,255,255,.35);border-radius:50%;z-index:0}.intro-screen:before{left:-260px;top:-160px}.intro-screen:after{right:-260px;bottom:-170px}.intro-screen>*{position:relative;z-index:1}.eyebrow{letter-spacing:.24em;font-size:12px;font-weight:900;color:#b44c72;margin:0 0 12px}.logo-badge{width:105px;height:105px;border-radius:50%;display:grid;place-items:center;background:linear-gradient(145deg,#ff8db6,#dc3e79);box-shadow:0 18px 35px rgba(153,36,82,.25),inset 0 0 0 8px rgba(255,255,255,.35);transform:rotate(-8deg)}.logo-badge span{font-size:50px;color:#fff;filter:drop-shadow(0 5px 0 #ad2e5e)}h1{font-family:"Shrikhand",Georgia,serif;font-weight:400;font-size:clamp(64px,11vw,118px);line-height:.92;margin:18px 0 0;color:#d83773;text-shadow:0 5px 0 #fff,0 10px 25px rgba(121,30,67,.18)}.subtitle{font-family:"Shrikhand",Georgia,serif;font-size:clamp(22px,4vw,35px);margin:7px 0;color:#712547}.intro-copy{max-width:620px;font-size:16px;line-height:1.65;margin:18px auto;color:#79445d}.how-to{display:flex;gap:12px;justify-content:center;margin:3px 0 24px;flex-wrap:wrap}.how-to div{width:142px;padding:12px...

JavaScript

(function () {
  "use strict";

  const $ = (selector) => document.querySelector(selector);
  const app = $("#pinkWinkApp");
  if (!app) return;

  const screens = {
    intro: $("#introScreen"),
    game: $("#gameScreen"),
    result: $("#resultScreen")
  };
  const street = $("#street");
  const characters = $("#characters");
  const followers = $("#followers");
  const beam = $("#winkBeam");
  const rival = $("#rival");
  const battlePanel = $("#battlePanel");
  const pinkBattleBar = $("#pinkBattleBar");
  const blueBattleBar = $("#blueBattleBar");

  const TYPES = [
    { name: "CASUAL WALKER", speed: 61, need: 0.95, points: 100, shirt: "#5a99ad", hair: "#5a3345" },
    { name: "COOL SKATER", speed: 88, need: 1.05, points: 180, shirt: "#6b6cb2", hair: "#34283b", fast: true },
    { name: "BUSY COMMUTER", speed: 76, need: 1.2, points: 150, shirt: "#d69b43", hair: "#352b34" },
    { name: "SUNGLASSES STAR", speed: 54, need: 1.55, points: 220, shirt: "#34485b", hair: "#171822" },
    { name: "PINK FAN · ×2", speed: 57, need: 0.75, points: 200, shirt: "#ed5d92", hair: "#88415d", bonus: 2 }
  ];

  let running = false;
  let score = 0;
  let joined = 0;
  let combo = 0;
  let bestCombo = 0;
  let timeLeft = 30;
  let spawnClock = 0;
  let battleCount = 0;
  let activeTarget = null;
  let holding = false;
  let battle = null;
  let lastFrame = 0;
  let raf = 0;
  let walkerId = 0;

  function showScreen(name) {
    Object.values(screens).forEach((screen) => screen.classList.remove("active"));
    screens[name].classList.add("active");
  }

  function createPersonParts() {
    return '<div class="person-shadow"></div><div class="hair"></div><div class="head"><i></i></div><div class="body"></div><div class="arm left"></div><div class="arm right"></div><div class="leg left"></div><div class="leg right"></div>';
  }

  function spawnWalker(forceNormal) {
    if (!running) return null;
    const type =...