Erste lauffähige Fassung: 3D-Raum, Echtzeit-Multiplayer (WebSocket), Python-IDE via Pyodide im Browser, eigener Arbeitsplatz mit Live-Code-Monitor. Modularer, self-hostbarer Aufbau (Three.js + Node/Express + ws), ohne CDN- Abhängigkeit zur Laufzeit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
93 lines
3.4 KiB
HTML
93 lines
3.4 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||
<title>VR ProgrammierHub</title>
|
||
<link rel="stylesheet" href="/css/style.css">
|
||
</head>
|
||
<body>
|
||
<div id="app"></div>
|
||
|
||
<div id="hud">
|
||
<div><b>VR ProgrammierHub</b></div>
|
||
<div>Bewegen: <b>W A S D</b> · Rennen <b>Shift</b></div>
|
||
<div>Umschauen: <b>Maus</b> (Klick fängt, Esc frei) · Pfeiltasten</div>
|
||
<div>Netz: <span id="net">–</span> · Online: <b id="count">0</b></div>
|
||
<div>FPS: <span id="fps">–</span> · Init: <span id="dbg">lädt…</span></div>
|
||
</div>
|
||
|
||
<div id="overlay">
|
||
<h1>VR <span>ProgrammierHub</span></h1>
|
||
<p>Gib dir einen Namen und betritt den Raum. Andere im selben Raum siehst du live als Avatar.
|
||
<span class="key">W A S D</span> laufen; zum Umschauen ins Bild klicken — die Maus wird gefangen und dreht die Blickrichtung frei, auch beim Laufen (<span class="key">Esc</span> gibt sie frei). Ohne Maus: <span class="key">← →</span> zum Drehen.</p>
|
||
<div class="row">
|
||
<input id="name" placeholder="Dein Name" maxlength="24" autocomplete="off">
|
||
<select id="role"><option value="student">Studierende:r</option><option value="teacher">Lehrperson</option></select>
|
||
</div>
|
||
<button id="startbtn">Raum betreten</button>
|
||
</div>
|
||
|
||
<div id="toolbar">
|
||
<button id="ideBtn">💻 Code</button>
|
||
<button id="helpBtn">✋ Hilfe anfragen</button>
|
||
</div>
|
||
|
||
<div id="sithint">🪑 An deinen Platz setzen — <span class="key">E</span></div>
|
||
|
||
<div id="ide">
|
||
<div id="ide-bar">
|
||
<span id="ide-title">💻 meine_uebung.py</span>
|
||
<span id="ide-status"></span>
|
||
<span class="spacer"></span>
|
||
<button id="ide-run">▶ Ausführen (Strg+Enter)</button>
|
||
<button id="ide-close">✕ Schließen (Esc)</button>
|
||
</div>
|
||
<textarea id="ide-editor" spellcheck="false"># Willkommen im ProgrammierHub 🐍
|
||
# Schreib Python und klick auf „Ausführen" (oder Strg+Enter).
|
||
|
||
class Punkt:
|
||
def __init__(self, x, y):
|
||
self.x = x
|
||
self.y = y
|
||
|
||
def __repr__(self):
|
||
return f"Punkt({self.x}, {self.y})"
|
||
|
||
|
||
for i in range(4):
|
||
print(i, "->", Punkt(i, i * i))
|
||
</textarea>
|
||
<pre id="ide-output"></pre>
|
||
</div>
|
||
|
||
<div id="err"></div>
|
||
|
||
<!-- Sicherheitsnetz: fängt Ladefehler global ab, unabhängig vom Modul. -->
|
||
<script>
|
||
window.__hubReady = false;
|
||
window.addEventListener('error', function (e) {
|
||
var b = document.getElementById('err'); if (!b) return;
|
||
b.style.display = 'block';
|
||
b.textContent = '⚠ Fehler (bitte an Claude weitergeben):\n' + (e.message || e.error || 'Ladefehler (Script/Modul)') + '\n' + (e.filename || '') + (e.lineno ? ':' + e.lineno : '');
|
||
});
|
||
window.addEventListener('unhandledrejection', function (e) {
|
||
var b = document.getElementById('err'); if (!b) return;
|
||
b.style.display = 'block';
|
||
b.textContent = '⚠ Promise-Fehler:\n' + (e.reason && (e.reason.stack || e.reason.message || e.reason));
|
||
});
|
||
// Watchdog: falls das Modul nicht startet (z. B. Netzwerk), klare Meldung statt stummem Blank.
|
||
setTimeout(function () {
|
||
if (window.__hubReady) return;
|
||
var b = document.getElementById('err'); if (!b) return;
|
||
b.style.display = 'block';
|
||
b.textContent = '⚠ Das 3D-Modul wurde nicht geladen (Netzwerk/Script-Fehler).\nBitte hart neu laden: Strg+Shift+R';
|
||
}, 4000);
|
||
</script>
|
||
|
||
<script type="importmap">
|
||
{ "imports": { "three": "/vendor/three.module.js" } }
|
||
</script>
|
||
<script type="module" src="/js/main.js"></script>
|
||
</body>
|
||
</html>
|