329 lines
13 KiB
HTML
329 lines
13 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||
<title>Pixel Slide — Premium 15-Puzzle Game</title>
|
||
<meta name="description" content="Experience the ultimate sliding puzzle game powered by PixiJS. Slices any custom image into dynamic sliding tiles across multiple difficulty levels." />
|
||
|
||
<!-- Google Fonts -->
|
||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Outfit:wght@500;600;700;800;900&display=swap" rel="stylesheet" />
|
||
|
||
<!-- PixiJS v8.20.0 -->
|
||
<script src="https://cdn.jsdelivr.net/npm/pixi.js@8.20.0/dist/pixi.min.js"></script>
|
||
|
||
<!-- Stylesheet -->
|
||
<link rel="stylesheet" href="style.css" />
|
||
</head>
|
||
<body>
|
||
<!-- Ambient background glow particles / decorative elements -->
|
||
<div class="ambient-bg">
|
||
<div class="glow-orb orb-1"></div>
|
||
<div class="glow-orb orb-2"></div>
|
||
<div class="glow-orb orb-3"></div>
|
||
<div class="grid-overlay"></div>
|
||
</div>
|
||
|
||
<div id="app-root">
|
||
<!-- TOP NAVIGATION BAR -->
|
||
<header class="app-header">
|
||
<div class="logo-group" id="btn-nav-home" role="button" tabindex="0" title="Return to Home">
|
||
<div class="logo-icon">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<rect x="3" y="3" width="7" height="7" rx="1.5"></rect>
|
||
<rect x="14" y="3" width="7" height="7" rx="1.5"></rect>
|
||
<rect x="3" y="14" width="7" height="7" rx="1.5"></rect>
|
||
<rect x="14" y="14" width="7" height="7" rx="1.5" stroke-dasharray="2 2"></rect>
|
||
</svg>
|
||
</div>
|
||
<span class="logo-text">PIXEL<span class="logo-highlight">SLIDE</span></span>
|
||
</div>
|
||
|
||
<div class="header-controls">
|
||
<button id="btn-sound-toggle" class="icon-btn" title="Toggle Sound (M)" aria-label="Toggle Sound">
|
||
<span id="sound-icon">🔊</span>
|
||
</button>
|
||
<button id="btn-header-leaderboard" class="glass-pill-btn" title="View Leaderboard">
|
||
<span>🏆</span> Leaderboard
|
||
</button>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- SCREEN: HOME -->
|
||
<main id="screen-home" class="screen active">
|
||
<div class="hero-section">
|
||
<h1 class="hero-title">
|
||
Master the <span class="gradient-text">Art of Sliding</span>
|
||
</h1>
|
||
<p class="hero-subtitle">
|
||
Upload any picture or choose from gallery presets. Sliced, shuffled, and rendered with ultra-smooth 60FPS physics.
|
||
</p>
|
||
|
||
<!-- Image source selection -->
|
||
<div class="upload-container">
|
||
<div class="upload-dropzone" id="upload-dropzone">
|
||
<input type="file" id="file-input" accept="image/*" class="visually-hidden" />
|
||
<div class="dropzone-icon">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
||
<polyline points="17 8 12 3 7 8"></polyline>
|
||
<line x1="12" y1="3" x2="12" y2="15"></line>
|
||
</svg>
|
||
</div>
|
||
<div class="dropzone-text">
|
||
<strong>Click to upload</strong> or drag and drop an image
|
||
</div>
|
||
<div class="dropzone-hint">Supports PNG, JPG, WebP, GIF (Max 15MB)</div>
|
||
</div>
|
||
|
||
<div class="preset-divider">
|
||
<span>OR CHOOSE A PRESET IMAGE</span>
|
||
</div>
|
||
|
||
<div class="preset-gallery" id="preset-gallery">
|
||
<!-- Preset items will be injected by JS -->
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
|
||
<!-- SCREEN: LEVEL SELECT -->
|
||
<section id="screen-level-select" class="screen">
|
||
<div class="screen-header">
|
||
<button id="btn-back-to-home" class="back-btn">
|
||
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M19 12H5M12 19l-7-7 7-7"/>
|
||
</svg>
|
||
Back
|
||
</button>
|
||
<div class="screen-title-group">
|
||
<h2>Select Difficulty</h2>
|
||
<p>Pick your grid complexity and test your spatial reasoning.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="level-selection-layout">
|
||
<div class="image-preview-card">
|
||
<div class="preview-header">
|
||
<span>Selected Image</span>
|
||
<button id="btn-change-image" class="text-link-btn">Change</button>
|
||
</div>
|
||
<div class="preview-canvas-wrapper">
|
||
<canvas id="preview-canvas"></canvas>
|
||
<div class="preview-grid-overlay" id="preview-grid-overlay"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="level-cards-grid" id="level-cards-grid">
|
||
<!-- Level Cards rendered by JS -->
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- SCREEN: GAMEPLAY -->
|
||
<section id="screen-game" class="screen">
|
||
<!-- HUD BAR -->
|
||
<div class="game-hud">
|
||
<div class="hud-left">
|
||
<button id="btn-game-pause" class="hud-btn pause-hud-btn" title="Pause Game (Esc)">
|
||
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2">
|
||
<rect x="6" y="4" width="4" height="16" rx="1"></rect>
|
||
<rect x="14" y="4" width="4" height="16" rx="1"></rect>
|
||
</svg>
|
||
<span>Pause</span>
|
||
</button>
|
||
<div class="level-badge" id="hud-level-badge">Medium 4×4</div>
|
||
</div>
|
||
|
||
<div class="hud-center">
|
||
<div class="stat-box timer-box">
|
||
<span class="stat-label">TIME</span>
|
||
<span class="stat-value" id="hud-timer">00:00.00</span>
|
||
</div>
|
||
<div class="stat-box moves-box">
|
||
<span class="stat-label">MOVES</span>
|
||
<span class="stat-value" id="hud-moves">0</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="hud-right">
|
||
<button id="btn-toggle-numbers" class="hud-btn icon-only" title="Toggle Tile Numbers (N)" aria-label="Toggle Numbers">
|
||
<span class="btn-icon">#️⃣</span>
|
||
</button>
|
||
<button id="btn-toggle-hint" class="hud-btn icon-only" title="Toggle Image Ghost Hint (H)" aria-label="Toggle Hint">
|
||
<span class="btn-icon">👁️</span>
|
||
</button>
|
||
<button id="btn-game-restart-quick" class="hud-btn icon-only" title="Restart Level (R)" aria-label="Restart Level">
|
||
<span class="btn-icon">🔄</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MAIN PUZZLE CANVAS CONTAINER -->
|
||
<div class="puzzle-viewport-container">
|
||
<div class="puzzle-board-frame" id="puzzle-board-frame">
|
||
<div id="pixi-canvas-mount"></div>
|
||
<!-- Ghost image overlay for hints -->
|
||
<div id="ghost-overlay" class="ghost-overlay"></div>
|
||
<!-- Shuffling overlay -->
|
||
<div id="shuffle-overlay" class="shuffle-overlay">
|
||
<div class="shuffle-spinner"></div>
|
||
<span>Shuffling tiles...</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- BOTTOM CONTROL BAR -->
|
||
<div class="game-footer-info">
|
||
<span class="tip-text">💡 Tap adjacent tiles or use <kbd>Arrow Keys</kbd> / <kbd>WASD</kbd> to slide</span>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- SCREEN: LEADERBOARD -->
|
||
<section id="screen-leaderboard" class="screen">
|
||
<div class="screen-header">
|
||
<button id="btn-back-from-leaderboard" class="back-btn">
|
||
<svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M19 12H5M12 19l-7-7 7-7"/>
|
||
</svg>
|
||
Back
|
||
</button>
|
||
<div class="screen-title-group">
|
||
<h2>Hall of Fame</h2>
|
||
<p>Global high scores sorted by fastest completion time and move count.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="leaderboard-container glass-card">
|
||
<div class="leaderboard-tabs" id="leaderboard-tabs">
|
||
<button class="tab-btn active" data-level="all">All Levels</button>
|
||
<button class="tab-btn" data-level="debug">Debug</button>
|
||
<button class="tab-btn" data-level="easy">Easy (3×3)</button>
|
||
<button class="tab-btn" data-level="medium">Medium (4×4)</button>
|
||
<button class="tab-btn" data-level="hard">Hard (5×5)</button>
|
||
<button class="tab-btn" data-level="insane">Insane (6×6)</button>
|
||
</div>
|
||
|
||
<div class="leaderboard-table-wrapper">
|
||
<table class="leaderboard-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Rank</th>
|
||
<th>Player</th>
|
||
<th>Difficulty</th>
|
||
<th>Time</th>
|
||
<th>Moves</th>
|
||
<th>Date</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="leaderboard-tbody">
|
||
<!-- Entries injected by JS -->
|
||
</tbody>
|
||
</table>
|
||
<div id="leaderboard-empty" class="leaderboard-empty">
|
||
<div class="empty-icon">🏆</div>
|
||
<p>No records found for this category.</p>
|
||
<span class="empty-sub">Complete a puzzle to claim the first spot!</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="leaderboard-footer">
|
||
<button id="btn-clear-leaderboard" class="danger-link-btn">Clear Records</button>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- OVERLAY: PAUSE MODAL -->
|
||
<div id="overlay-pause" class="modal-overlay">
|
||
<div class="modal-card pause-card">
|
||
<div class="modal-icon-badge">⏸</div>
|
||
<h2>Game Paused</h2>
|
||
<p>Take a breath. The timer is currently stopped.</p>
|
||
|
||
<div class="modal-stats-row">
|
||
<div class="modal-stat">
|
||
<span class="m-label">Elapsed Time</span>
|
||
<span class="m-val" id="pause-modal-time">00:00.00</span>
|
||
</div>
|
||
<div class="modal-stat">
|
||
<span class="m-label">Moves Made</span>
|
||
<span class="m-val" id="pause-modal-moves">0</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="modal-actions-stacked">
|
||
<button id="btn-pause-resume" class="btn btn-primary btn-glow">
|
||
<span>▶</span> Resume Game
|
||
</button>
|
||
<button id="btn-pause-restart" class="btn btn-secondary">
|
||
<span>🔄</span> Restart Puzzle
|
||
</button>
|
||
<button id="btn-pause-change-level" class="btn btn-outline">
|
||
<span>🎮</span> Change Difficulty
|
||
</button>
|
||
<button id="btn-pause-quit" class="btn btn-danger-outline">
|
||
<span>🏠</span> Quit to Menu
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- OVERLAY: VICTORY MODAL -->
|
||
<div id="overlay-victory" class="modal-overlay">
|
||
<canvas id="confetti-canvas" class="confetti-canvas"></canvas>
|
||
<div class="modal-card victory-card">
|
||
<div class="victory-header">
|
||
<div class="crown-icon">👑</div>
|
||
<h2>Puzzle Solved!</h2>
|
||
<p class="victory-tagline">Flawless spatial mastery. Here are your final stats:</p>
|
||
</div>
|
||
|
||
<div class="victory-stats-grid">
|
||
<div class="v-stat-card highlight">
|
||
<span class="v-label">TIME</span>
|
||
<span class="v-value" id="victory-time">00:00.00</span>
|
||
</div>
|
||
<div class="v-stat-card">
|
||
<span class="v-label">MOVES</span>
|
||
<span class="v-value" id="victory-moves">0</span>
|
||
</div>
|
||
<div class="v-stat-card">
|
||
<span class="v-label">DIFFICULTY</span>
|
||
<span class="v-value" id="victory-difficulty">Medium</span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Name submit form -->
|
||
<form id="victory-form" class="victory-form" onsubmit="return false;">
|
||
<label for="player-name-input">Save to Leaderboard</label>
|
||
<div class="input-with-btn">
|
||
<input type="text" id="player-name-input" maxlength="20" placeholder="Enter your name" required autocomplete="off" />
|
||
<button type="submit" id="btn-save-score" class="btn btn-primary">
|
||
Save Score
|
||
</button>
|
||
</div>
|
||
<div id="save-feedback" class="save-feedback"></div>
|
||
</form>
|
||
|
||
<div class="victory-actions">
|
||
<button id="btn-victory-replay" class="btn btn-secondary">
|
||
<span>🔄</span> Play Again
|
||
</button>
|
||
<button id="btn-victory-levels" class="btn btn-primary">
|
||
<span>🎮</span> Select Level
|
||
</button>
|
||
<button id="btn-victory-leaderboard" class="btn btn-outline">
|
||
<span>🏆</span> Leaderboard
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Game script -->
|
||
<script src="game.js"></script>
|
||
</body>
|
||
</html>
|