Files

329 lines
13 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!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>