All checks were successful
Build / build (push) Successful in 1m20s
Major refactoring of the UI layer to use Svelte components: - Replace inline HTML with modular Svelte components - Add authentication system with UserProfile component - Implement navigation store for view management - Create comprehensive settings and controls screens - Add level editor with JSON validation - Implement progression tracking system - Update level configurations and base station model 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
565 lines
23 KiB
Plaintext
565 lines
23 KiB
Plaintext
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8" />
|
||
<meta content="width=device-width, initial-scale=1, height=device-height" name="viewport">
|
||
<link href="/styles.css" rel="stylesheet">
|
||
<title>Space Game</title>
|
||
<script>
|
||
navigator.serviceWorker.getRegistrations().then(registrations => {
|
||
for (const registration of registrations) {
|
||
registration.unregister();
|
||
}
|
||
});
|
||
</script>
|
||
</head>
|
||
<body>
|
||
<!-- Game View -->
|
||
<div data-view="game">
|
||
<canvas id="gameCanvas"></canvas>
|
||
|
||
<!-- Semantic Header with Navigation -->
|
||
<header class="app-header" id="appHeader" style="display: none;">
|
||
<div class="header-content">
|
||
<div class="header-left">
|
||
<h1 class="app-title">Space Combat VR</h1>
|
||
</div>
|
||
<nav class="header-nav">
|
||
<div id="userProfile"></div>
|
||
<a href="#/editor" class="nav-link editor-link">📝 Level Editor</a>
|
||
<a href="#/controls" class="nav-link controls-link">🎮 Controls</a>
|
||
<a href="#/settings" class="nav-link settings-link">⚙️ Settings</a>
|
||
</nav>
|
||
</div>
|
||
</header>
|
||
|
||
<div id="mainDiv">
|
||
<div id="loadingDiv"></div>
|
||
<div id="levelSelect">
|
||
|
||
<!-- Hero Section -->
|
||
<div class="hero">
|
||
<h1 class="hero-title">🚀 Space Combat VR</h1>
|
||
<p class="hero-subtitle">
|
||
Pilot your spaceship through asteroid fields and complete missions
|
||
</p>
|
||
</div>
|
||
|
||
<!-- Level Selection Section -->
|
||
<div class="level-section">
|
||
<h2 class="level-header">Your Mission</h2>
|
||
<p class="level-description">
|
||
Complete levels to unlock new challenges and the level editor
|
||
</p>
|
||
<div id="levelCardsContainer" class="card-container">
|
||
<!-- Level cards will be dynamically populated from localStorage -->
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Controls Section (Collapsed by default) -->
|
||
<details class="controls-info">
|
||
<summary>
|
||
🎮 How to Play (Click to expand)
|
||
</summary>
|
||
<div class="controls-grid">
|
||
<div class="control-section">
|
||
<h3>VR Controllers (Required for VR)</h3>
|
||
<ul>
|
||
<li><strong>Left Thumbstick:</strong> Move forward/backward and yaw left/right</li>
|
||
<li><strong>Right Thumbstick:</strong> Pitch up/down and Roll left/right</li>
|
||
<li><strong>Front Trigger:</strong> Fire weapon</li>
|
||
</ul>
|
||
</div>
|
||
<div class="control-section">
|
||
<h3>Desktop Controls (Preview Mode)</h3>
|
||
<ul>
|
||
<li><strong>W/S:</strong> Move forward/backward</li>
|
||
<li><strong>A/D:</strong> Yaw left/right</li>
|
||
<li><strong>Arrow Up/Down:</strong> Pitch up/down</li>
|
||
<li><strong>Arrow Left/Right:</strong> Roll left/right</li>
|
||
<li><strong>Space:</strong> Fire weapon</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<p class="controls-note">
|
||
⚠️ <strong>Note:</strong> This game is designed for VR headsets with controllers. Desktop controls are provided for preview and testing purposes only.
|
||
</p>
|
||
</details>
|
||
|
||
<!-- Test Buttons (Hidden by default) -->
|
||
<div class="test-buttons-container" id="testButtonsContainer" style="display: none;">
|
||
<button id="testLevelBtn" class="test-level-button">
|
||
🧪 Test Scene (Debug)
|
||
</button>
|
||
<button id="viewReplaysBtn" class="test-level-button">
|
||
📹 View Replays
|
||
</button>
|
||
<br>
|
||
<a href="#/editor" class="level-create-link">
|
||
+ Create New Level
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Editor View -->
|
||
<div data-view="editor" style="display: none;">
|
||
<div class="editor-container">
|
||
<a href="#/" class="back-link">← Back to Game</a>
|
||
|
||
<h1>🚀 Level Editor</h1>
|
||
<p class="subtitle">Configure and generate custom level configurations</p>
|
||
|
||
<div class="section">
|
||
<h2>Difficulty Presets</h2>
|
||
<div class="preset-buttons">
|
||
<button class="preset-btn" data-difficulty="recruit">Recruit</button>
|
||
<button class="preset-btn" data-difficulty="pilot">Pilot</button>
|
||
<button class="preset-btn" data-difficulty="captain">Captain</button>
|
||
<button class="preset-btn" data-difficulty="commander">Commander</button>
|
||
<button class="preset-btn" data-difficulty="test">Test</button>
|
||
<button class="preset-btn" data-difficulty="custom">Custom</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="editor-grid">
|
||
<!-- Basic Settings -->
|
||
<div class="section">
|
||
<h2>⚙️ Basic Settings</h2>
|
||
<div class="form-group">
|
||
<label for="levelName">Level Name</label>
|
||
<input type="text" id="levelName" placeholder="my-custom-level">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="difficulty">Difficulty</label>
|
||
<select id="difficulty">
|
||
<option value="recruit">Recruit</option>
|
||
<option value="pilot">Pilot</option>
|
||
<option value="captain">Captain</option>
|
||
<option value="commander">Commander</option>
|
||
<option value="test">Test</option>
|
||
<option value="custom">Custom</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="author">Author (Optional)</label>
|
||
<input type="text" id="author" placeholder="Your name">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="description">Description (Optional)</label>
|
||
<input type="text" id="description" placeholder="Level description">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Ship Configuration -->
|
||
<div class="section">
|
||
<h2>🚀 Ship</h2>
|
||
<div class="form-group">
|
||
<label>Position</label>
|
||
<div class="vector-input">
|
||
<div>
|
||
<div class="vector-label">X</div>
|
||
<input type="number" id="shipX" value="0" step="0.1">
|
||
</div>
|
||
<div>
|
||
<div class="vector-label">Y</div>
|
||
<input type="number" id="shipY" value="1" step="0.1">
|
||
</div>
|
||
<div>
|
||
<div class="vector-label">Z</div>
|
||
<input type="number" id="shipZ" value="0" step="0.1">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Start Base Configuration -->
|
||
<div class="section">
|
||
<h2>🎯 Start Base</h2>
|
||
<div class="form-group">
|
||
<label>Position</label>
|
||
<div class="vector-input">
|
||
<div>
|
||
<div class="vector-label">X</div>
|
||
<input type="number" id="baseX" value="0" step="0.1">
|
||
</div>
|
||
<div>
|
||
<div class="vector-label">Y</div>
|
||
<input type="number" id="baseY" value="0" step="0.1">
|
||
</div>
|
||
<div>
|
||
<div class="vector-label">Z</div>
|
||
<input type="number" id="baseZ" value="0" step="0.1">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Base GLB Path</label>
|
||
<input type="text" id="baseGlbPath" value="base.glb" placeholder="base.glb">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Sun Configuration -->
|
||
<div class="section">
|
||
<h2>☀️ Sun</h2>
|
||
<div class="form-group">
|
||
<label>Position</label>
|
||
<div class="vector-input">
|
||
<div>
|
||
<div class="vector-label">X</div>
|
||
<input type="number" id="sunX" value="0" step="1">
|
||
</div>
|
||
<div>
|
||
<div class="vector-label">Y</div>
|
||
<input type="number" id="sunY" value="0" step="1">
|
||
</div>
|
||
<div>
|
||
<div class="vector-label">Z</div>
|
||
<input type="number" id="sunZ" value="400" step="1">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="sunDiameter">Diameter</label>
|
||
<input type="number" id="sunDiameter" value="50" step="1" min="1">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Planet Generation -->
|
||
<div class="section">
|
||
<h2>🪐 Planets</h2>
|
||
<div class="form-group">
|
||
<label for="planetCount">Count</label>
|
||
<input type="number" id="planetCount" value="12" min="0" max="50">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="planetMinDiam">Min Diameter</label>
|
||
<input type="number" id="planetMinDiam" value="100" step="10" min="10">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="planetMaxDiam">Max Diameter</label>
|
||
<input type="number" id="planetMaxDiam" value="200" step="10" min="10">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="planetMinDist">Min Distance from Sun</label>
|
||
<input type="number" id="planetMinDist" value="1000" step="100" min="100">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="planetMaxDist">Max Distance from Sun</label>
|
||
<input type="number" id="planetMaxDist" value="2000" step="100" min="100">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Asteroid Generation -->
|
||
<div class="section">
|
||
<h2>☄️ Asteroids</h2>
|
||
<div class="form-group">
|
||
<label for="asteroidCount">Count</label>
|
||
<input type="number" id="asteroidCount" value="20" min="1" max="200">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="forceMultiplier">Force Multiplier</label>
|
||
<input type="number" id="forceMultiplier" value="1.2" step="0.1" min="0.1">
|
||
<div class="help-text">Controls asteroid speed</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="asteroidMinSize">Min Size</label>
|
||
<input type="number" id="asteroidMinSize" value="2" step="0.5" min="0.5">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="asteroidMaxSize">Max Size</label>
|
||
<input type="number" id="asteroidMaxSize" value="7" step="0.5" min="0.5">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="asteroidMinDist">Min Distance</label>
|
||
<input type="number" id="asteroidMinDist" value="100" step="10" min="10">
|
||
<div class="help-text">Distance from start base</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="asteroidMaxDist">Max Distance</label>
|
||
<input type="number" id="asteroidMaxDist" value="250" step="10" min="10">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="button-group">
|
||
<button class="btn-primary" id="generateBtn">Generate & Save</button>
|
||
<button class="btn-success" id="downloadBtn">Download JSON</button>
|
||
<button class="btn-secondary" id="copyBtn">Copy to Clipboard</button>
|
||
</div>
|
||
|
||
<div class="output-section" id="savedLevelsSection">
|
||
<h2>💾 Saved Levels</h2>
|
||
<div id="savedLevelsList"></div>
|
||
</div>
|
||
|
||
<div class="output-section editor-json-output" id="outputSection" style="display: none;">
|
||
<h2>Generated JSON</h2>
|
||
<p class="editor-json-note">
|
||
You can edit this JSON directly and save your changes.
|
||
</p>
|
||
<textarea id="jsonEditor" class="json-editor-textarea"></textarea>
|
||
<div class="editor-json-buttons">
|
||
<button class="btn-primary" id="saveEditedJsonBtn">Save Edited JSON</button>
|
||
<button class="btn-secondary" id="validateJsonBtn">Validate JSON</button>
|
||
</div>
|
||
<div id="jsonValidationMessage" class="json-validation-message"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Controller Mapping View -->
|
||
<div data-view="controls" style="display: none;">
|
||
<div class="editor-container">
|
||
<a href="#/" class="back-link">← Back to Game</a>
|
||
|
||
<h1>🎮 Controller Mapping</h1>
|
||
<p class="subtitle">Customize VR controller button and stick mappings</p>
|
||
|
||
<div class="settings-grid">
|
||
<!-- Left Stick Section -->
|
||
<div class="section">
|
||
<h2>🕹️ Left Stick</h2>
|
||
<p class="settings-description">
|
||
Configure what actions the left thumbstick controls.
|
||
</p>
|
||
|
||
<div class="form-group">
|
||
<label for="leftStickX">Left Stick X-Axis (Left/Right)</label>
|
||
<select id="leftStickX" class="settings-select"></select>
|
||
<label class="checkbox-label" style="margin-top: 8px;">
|
||
<input type="checkbox" id="invertLeftStickX" class="settings-checkbox">
|
||
<span>Invert this axis</span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="leftStickY">Left Stick Y-Axis (Up/Down)</label>
|
||
<select id="leftStickY" class="settings-select"></select>
|
||
<label class="checkbox-label" style="margin-top: 8px;">
|
||
<input type="checkbox" id="invertLeftStickY" class="settings-checkbox">
|
||
<span>Invert this axis</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Right Stick Section -->
|
||
<div class="section">
|
||
<h2>🕹️ Right Stick</h2>
|
||
<p class="settings-description">
|
||
Configure what actions the right thumbstick controls.
|
||
</p>
|
||
|
||
<div class="form-group">
|
||
<label for="rightStickX">Right Stick X-Axis (Left/Right)</label>
|
||
<select id="rightStickX" class="settings-select"></select>
|
||
<label class="checkbox-label" style="margin-top: 8px;">
|
||
<input type="checkbox" id="invertRightStickX" class="settings-checkbox">
|
||
<span>Invert this axis</span>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="rightStickY">Right Stick Y-Axis (Up/Down)</label>
|
||
<select id="rightStickY" class="settings-select"></select>
|
||
<label class="checkbox-label" style="margin-top: 8px;">
|
||
<input type="checkbox" id="invertRightStickY" class="settings-checkbox">
|
||
<span>Invert this axis</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Button Mappings Section -->
|
||
<div class="section">
|
||
<h2>🔘 Button Mappings</h2>
|
||
<p class="settings-description">
|
||
Configure what actions each controller button performs.
|
||
</p>
|
||
|
||
<div class="form-group">
|
||
<label for="trigger">Trigger (Index Finger)</label>
|
||
<select id="trigger" class="settings-select"></select>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="aButton">A Button (Right Controller)</label>
|
||
<select id="aButton" class="settings-select"></select>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="bButton">B Button (Right Controller)</label>
|
||
<select id="bButton" class="settings-select"></select>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="xButton">X Button (Left Controller)</label>
|
||
<select id="xButton" class="settings-select"></select>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="yButton">Y Button (Left Controller)</label>
|
||
<select id="yButton" class="settings-select"></select>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="squeeze">Squeeze/Grip Button</label>
|
||
<select id="squeeze" class="settings-select"></select>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Info Section -->
|
||
<div class="section">
|
||
<h2>ℹ️ Action Guide</h2>
|
||
<div class="settings-info-content">
|
||
<p><strong class="settings-label">Yaw:</strong> Turn left/right (rotate around vertical axis)</p>
|
||
<p><strong class="settings-label">Pitch:</strong> Nose up/down (rotate around horizontal axis)</p>
|
||
<p><strong class="settings-label">Roll:</strong> Barrel roll (rotate around forward axis)</p>
|
||
<p><strong class="settings-label">Forward:</strong> Forward and backward thrust</p>
|
||
<p><strong class="settings-label">None:</strong> No action assigned</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Storage Info -->
|
||
<div class="section">
|
||
<h2>💾 Storage Info</h2>
|
||
<div class="settings-info-content">
|
||
<p>Controller mappings are automatically saved to your browser's local storage and will persist between sessions.</p>
|
||
<p class="settings-warning">
|
||
⚠️ Note: Changes will take effect when you start a new level. Restart the current level to see changes.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="button-group">
|
||
<button class="btn-primary" id="saveControlsBtn">💾 Save Mapping</button>
|
||
<button class="btn-secondary" id="resetControlsBtn">🔄 Reset to Default</button>
|
||
<button class="btn-secondary" id="testControlsBtn">👁️ Preview Mapping</button>
|
||
</div>
|
||
|
||
<div id="controlsMessage" class="settings-message"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Settings View -->
|
||
<div data-view="settings" style="display: none;">
|
||
<div class="editor-container">
|
||
<a href="#/" class="back-link">← Back to Game</a>
|
||
|
||
<h1>⚙️ Game Settings</h1>
|
||
<p class="subtitle">Configure graphics quality and physics settings</p>
|
||
|
||
<div class="settings-grid">
|
||
<!-- Physics Settings -->
|
||
<div class="section">
|
||
<h2>⚛️ Physics</h2>
|
||
<p class="settings-description">
|
||
Disabling physics can significantly improve performance but will prevent gameplay.
|
||
</p>
|
||
|
||
<div class="form-group">
|
||
<label class="checkbox-label">
|
||
<input type="checkbox" id="physicsEnabled" class="settings-checkbox">
|
||
<span>Enable Physics</span>
|
||
</label>
|
||
<div class="help-text">
|
||
Required for collisions, shooting, and asteroid movement. Disabling this will prevent gameplay but may help with debugging or viewing the scene.
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Debug Settings -->
|
||
<div class="section">
|
||
<h2>🐛 Developer</h2>
|
||
<p class="settings-description">
|
||
Enable debug logging to console for troubleshooting and development.
|
||
</p>
|
||
|
||
<div class="form-group">
|
||
<label class="checkbox-label">
|
||
<input type="checkbox" id="debugEnabled" class="settings-checkbox">
|
||
<span>Enable Debug Logging</span>
|
||
</label>
|
||
<div class="help-text">
|
||
When enabled, debug messages will be shown in the browser console. Useful for development and troubleshooting issues.
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Ship Physics Settings -->
|
||
<div class="section">
|
||
<h2>🚀 Ship Physics</h2>
|
||
<p class="settings-description">
|
||
Advanced tuning parameters for ship movement and handling. Adjust these to customize how the ship responds to controls.
|
||
</p>
|
||
|
||
<div class="form-group">
|
||
<label for="maxLinearVelocity">Max Linear Velocity</label>
|
||
<input type="number" id="maxLinearVelocity" value="200" step="10" min="50" max="1000">
|
||
<div class="help-text">
|
||
Maximum forward/backward speed of the ship. Higher values allow faster movement.
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="maxAngularVelocity">Max Angular Velocity</label>
|
||
<input type="number" id="maxAngularVelocity" value="1.4" step="0.1" min="0.5" max="5.0">
|
||
<div class="help-text">
|
||
Maximum rotation speed of the ship. Higher values allow faster turning.
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="linearForceMultiplier">Linear Force Multiplier</label>
|
||
<input type="number" id="linearForceMultiplier" value="800" step="50" min="100" max="3000">
|
||
<div class="help-text">
|
||
Acceleration power for forward/backward thrust. Higher values = faster acceleration.
|
||
</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="angularForceMultiplier">Angular Force Multiplier</label>
|
||
<input type="number" id="angularForceMultiplier" value="15" step="1" min="5" max="50">
|
||
<div class="help-text">
|
||
Torque power for rotation. Higher values = faster rotational acceleration.
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Info Section -->
|
||
<div class="section">
|
||
<h2>ℹ️ Quality Level Guide</h2>
|
||
<div class="settings-info-content">
|
||
<p><strong class="settings-label">Wireframe:</strong> Minimal rendering, shows mesh structure only. Best for debugging or very low-end devices.</p>
|
||
<p><strong class="settings-label">Simple Material:</strong> Basic solid colors without textures. Good performance with basic visuals.</p>
|
||
<p><strong class="settings-label">Full Texture:</strong> Standard textures with procedural generation. Recommended for most users.</p>
|
||
<p><strong class="settings-label">PBR Texture:</strong> Physically-based rendering with enhanced materials. Best visual quality but higher GPU usage.</p>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Current Config Display -->
|
||
<div class="section">
|
||
<h2>💾 Storage Info</h2>
|
||
<div class="settings-info-content">
|
||
<p>Settings are automatically saved to your browser's local storage and will persist between sessions.</p>
|
||
<p class="settings-warning">
|
||
⚠️ Note: Changes will take effect when you start a new level. Restart the current level to see changes.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="button-group">
|
||
<button class="btn-primary" id="saveSettingsBtn">💾 Save Settings</button>
|
||
<button class="btn-secondary" id="resetSettingsBtn">🔄 Reset to Defaults</button>
|
||
</div>
|
||
|
||
<div id="settingsMessage" class="settings-message"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script type="module" src="/src/main.ts"></script>
|
||
</body>
|
||
</html>
|