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