Some checks failed
Build / build (push) Failing after 23s
Added TestLevel class for debugging with progressive box creation and performance tracking. Includes comprehensive debug logging throughout the explosion system to diagnose Meta Quest issues. Key changes: - New TestLevel with 1-1000 box spawning (doubling each 5s iteration) - Performance metrics logging (FPS, triangle count, mesh count) - Direct triangle computation from mesh geometry - Extensive explosion system debug logging - Fixed observable timing issue (initialize after listener registration) - Material freezing optimization 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
410 lines
17 KiB
HTML
410 lines
17 KiB
HTML
<!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>
|
||
<link rel="prefetch" href="/background.mp3"/>
|
||
<link rel="prefetch" href="/8192.webp"/>
|
||
</head>
|
||
<body>
|
||
<!-- Game View -->
|
||
<div data-view="game">
|
||
<canvas id="gameCanvas"></canvas>
|
||
<a href="#/editor" class="editor-link">📝 Level Editor</a>
|
||
<a href="#/settings" class="settings-link">⚙️ Settings</a>
|
||
<div id="mainDiv">
|
||
<div id="loadingDiv">Loading...</div>
|
||
<div id="levelSelect">
|
||
|
||
|
||
<!-- Controls Section -->
|
||
<div class="controls-info">
|
||
<h2>🎮 How to Play</h2>
|
||
<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 Keys:</strong> Pitch up, down</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>
|
||
</div>
|
||
<h1>Select Your Level</h1>
|
||
<div id="levelCardsContainer" class="card-container">
|
||
<!-- Level cards will be dynamically populated from localStorage -->
|
||
</div>
|
||
<div style="text-align: center; margin-top: 20px;">
|
||
<button id="testLevelBtn" class="test-level-button">
|
||
🧪 Test Scene (Debug)
|
||
</button>
|
||
<br>
|
||
<a href="#/editor" style="color: #4CAF50; text-decoration: none; font-size: 1.1em;">
|
||
+ 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 for="baseDiameter">Diameter</label>
|
||
<input type="number" id="baseDiameter" value="10" step="1" min="1">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="baseHeight">Height</label>
|
||
<input type="number" id="baseHeight" value="1" step="0.1" min="0.1">
|
||
</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" id="outputSection" style="display: none;">
|
||
<h2>Generated JSON</h2>
|
||
<p style="color: #aaa; font-size: 0.9em; margin-bottom: 15px;">
|
||
You can edit this JSON directly and save your changes.
|
||
</p>
|
||
<textarea id="jsonEditor" style="
|
||
width: 100%;
|
||
min-height: 400px;
|
||
background: #0a0a0a;
|
||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||
border-radius: 5px;
|
||
padding: 15px;
|
||
font-family: 'Courier New', monospace;
|
||
font-size: 0.85em;
|
||
color: #e0e0e0;
|
||
line-height: 1.5;
|
||
resize: vertical;
|
||
box-sizing: border-box;
|
||
"></textarea>
|
||
<div style="display: flex; gap: 10px; margin-top: 15px; justify-content: flex-end;">
|
||
<button class="btn-primary" id="saveEditedJsonBtn">Save Edited JSON</button>
|
||
<button class="btn-secondary" id="validateJsonBtn">Validate JSON</button>
|
||
</div>
|
||
<div id="jsonValidationMessage" style="margin-top: 10px;"></div>
|
||
</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">
|
||
<!-- Graphics Settings -->
|
||
<div class="section">
|
||
<h2>🎨 Graphics Quality</h2>
|
||
<p style="color: #aaa; font-size: 0.9em; margin-bottom: 20px;">
|
||
Higher quality settings may impact performance on lower-end devices.
|
||
</p>
|
||
|
||
<div class="form-group">
|
||
<label for="planetTextureLevel">Planet Quality</label>
|
||
<select id="planetTextureLevel">
|
||
<option value="WIREFRAME">Wireframe (Lowest)</option>
|
||
<option value="SIMPLE_MATERIAL">Simple Material</option>
|
||
<option value="FULL_TEXTURE">Full Texture (Recommended)</option>
|
||
<option value="PBR_TEXTURE">PBR Texture (Highest)</option>
|
||
</select>
|
||
<div class="help-text">Controls planet rendering quality and detail</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="asteroidTextureLevel">Asteroid Quality</label>
|
||
<select id="asteroidTextureLevel">
|
||
<option value="WIREFRAME">Wireframe (Lowest)</option>
|
||
<option value="SIMPLE_MATERIAL">Simple Material</option>
|
||
<option value="FULL_TEXTURE">Full Texture (Recommended)</option>
|
||
<option value="PBR_TEXTURE">PBR Texture (Highest)</option>
|
||
</select>
|
||
<div class="help-text">Controls asteroid rendering quality and detail</div>
|
||
</div>
|
||
|
||
<div class="form-group">
|
||
<label for="sunTextureLevel">Sun Quality</label>
|
||
<select id="sunTextureLevel">
|
||
<option value="WIREFRAME">Wireframe (Lowest)</option>
|
||
<option value="SIMPLE_MATERIAL">Simple Material</option>
|
||
<option value="FULL_TEXTURE">Full Texture (Recommended)</option>
|
||
<option value="PBR_TEXTURE">PBR Texture (Highest)</option>
|
||
</select>
|
||
<div class="help-text">Controls sun rendering quality</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Physics Settings -->
|
||
<div class="section">
|
||
<h2>⚛️ Physics</h2>
|
||
<p style="color: #aaa; font-size: 0.9em; margin-bottom: 20px;">
|
||
Disabling physics can significantly improve performance but will prevent gameplay.
|
||
</p>
|
||
|
||
<div class="form-group">
|
||
<label style="display: flex; align-items: center; cursor: pointer; user-select: none;">
|
||
<input type="checkbox" id="physicsEnabled" style="
|
||
width: 20px;
|
||
height: 20px;
|
||
margin-right: 10px;
|
||
cursor: pointer;
|
||
accent-color: #4CAF50;
|
||
">
|
||
<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>
|
||
|
||
<!-- Info Section -->
|
||
<div class="section">
|
||
<h2>ℹ️ Quality Level Guide</h2>
|
||
<div style="color: #ccc; font-size: 0.9em; line-height: 1.8;">
|
||
<p><strong style="color: #4CAF50;">Wireframe:</strong> Minimal rendering, shows mesh structure only. Best for debugging or very low-end devices.</p>
|
||
<p><strong style="color: #4CAF50;">Simple Material:</strong> Basic solid colors without textures. Good performance with basic visuals.</p>
|
||
<p><strong style="color: #4CAF50;">Full Texture:</strong> Standard textures with procedural generation. Recommended for most users.</p>
|
||
<p><strong style="color: #4CAF50;">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 style="color: #ccc; font-size: 0.9em; line-height: 1.8;">
|
||
<p>Settings are automatically saved to your browser's local storage and will persist between sessions.</p>
|
||
<p style="color: #FF9800; margin-top: 10px;">
|
||
⚠️ 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" style="
|
||
text-align: center;
|
||
margin-top: 20px;
|
||
font-size: 1.1em;
|
||
opacity: 0;
|
||
transition: opacity 0.3s;
|
||
"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script type="module" src="/src/main.ts"></script>
|
||
</body>
|
||
</html>
|