Files
mesh-configs/skills/creative/web-3d-graphics/SKILL.md
T

5.3 KiB

name, description, version, tags
name description version tags
web-3d-graphics Add real 3D to web pages with Three.js, hosted locally. 1.0
threejs
webgl
3d
frontend

Web-3D-Grafiken (Three.js, lokal gehostet)

Wann

Nutzer will "richtige 3D-Grafiken" auf einer Webseite (VPS, netcup). Recurring für diesen Nutzer (TicTacToe 3D, PersoEnt-Dashboards usw.).

Kernsätze (alle VERIFIZIERT an tictactoe.perfekt-ohne-en.de)

1. Abhängigkeit lokal hosten — KEIN CDN

  • DSGVO-sauber + keine Drittanbieter-Abhängigkeit: three.js in das Project-lib/-Verzeichnis laden.
  • UMD-Version (global THREE) für einfaches <script src="lib/three.js">: nutze r128 von cdnjs: curl -sL -o lib/three.js https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js
  • NICHT unpkg r160 — das ist ESM-only (build/three.min.js existiert dort nicht), wirft Deprecation-Warnungen und ist nicht global verfügbar. r128 ist ein Ordner, global THREE.
  • nach curl: grep -c REVISION lib/three.js → 1 bestätigt globale UMD; Syntax parsen mit node -e "require(...)".

2. CRITICAL — Geometrie hat KEINE .rotation

  • new THREE.BoxGeometry(...) ist eine BufferGeometry: Zugriff geometry.rotation.z = ... wirft TypeError: Cannot set properties of undefined (setting 'z').
  • Fix: Rotations-Methode direkt auf der Geometrie: geom.rotateZ(Math.PI/4) / rotateY / rotateX.
  • Nur Meshes/Groups (Object3D) haben .position/.rotation — Geometrien nicht.
  • Diagnose: der Fehler gibt keine Dateizeilen in der Konsole an, nur den Stack im eigenen browser_console-Aufruf; teste Geometrie-Erzeugung isoliert (Material/Box/Torus einzeln) um die fehlerhafte Zeile zu isolieren.

3. Standard-Setup (bewährt)

  • renderer = new THREE.WebGLRenderer({canvas, alpha:true, antialias:true}); renderer.setPixelRatio(min(devicePixelRatio,2))
  • camera = PerspectiveCamera(40, w/h, 0.1, 100); z.B. position(0,2.6,5.2), lookAt(0,0,0)
  • Licht: AmbientLight(0xffffff,0.7) + DirectionalLight(0xffffff,0.9) bei (3,5,4)
  • 3D-Marker-Muster:
    • X = Group mit 2 gekreuzten BoxGeometry, je rotateZ(±PI/4)
    • O = TorusGeometry(0.42,0.14,16,40) mit rotation.x=PI/2
    • Materialien MeshPhysicalMaterial({metalness,roughness}) für Glanz
  • Animation: requestAnimationFrame-Loop.
  • Wachsen/Platzieren: Scale von 0.01 → 1 in Tween (ease-out cubic), danach Spin-Rotation um eigene Achse

4. CRITICAL — Interaktion: NICHT per Canvas-Klick-Mapping, sondern 2D-Overlay-Grid

Der Nutzer verlor, weil er "blind klickte und die Position nicht traf". Verwirf den Ansatz, Klicks auf dem 3D-canvas per perspektivischer Koordinaten-Mapping aufzunehmen (Normalized-Coords → proportional auf Raster) — das ist bei einer PerspectiveCamera ungenau und unspielbar. Stattdessen die robuste Architektur:

.stage (position:relative)
  └── <canvas id="level">       ← reines 3D-Rendering (Steine, Gitter, Licht)
  └── <div class="grid-overlay"> ← UNICHTBARES 2D-Grid, absolut über dem Canvas
         └── 9 <div class="grid-cell" data-i data-onclick>  ← fängt Klicks EXAKT
  • grid-overlay { position:absolute; inset:0; display:grid; grid-template-columns/rows:repeat(3,1fr) }
  • Jede Zelle ist ein eigener <div> mit onclick=makeMove(i) — keine Perspektiv-Mathematik, jeder Treffer deterministisch.
  • 3D-Canvas ist rein dekorativ; die Klick-Interaktion läuft 100% über das HTML-Overlay.
  • Hover-Feedback (.grid-cell:hover { background: rgba(blue,.12) }) auf dem Overlay, nicht auf dem Canvas.
  • Überprüfbar: Spielzug via document.querySelector('.grid-cell[data-i="4"]').click() statt fake-Koordinaten.

5. Verifikation (Browser-Pflicht)

Drei-D-Seiten laufen nur im Browser (WebGL). Nicht nur curl. Nutze browser_navigate + browser_console:

  1. browser_navigate(url) — check: Seite lädt (Titel + enthält erwartete Buttons).
  2. browser_console (ohne expression) — keine js_errors/console_messages.
  3. Funktions-Test via browser_console mit Expression: init() + makeMove(idx) in try/catch; prüfe board + Anzahl platzierter Steine (meshes.filter(m=>m!==null).length). Bei KI-Zug (setTimeout) mit Promise+setTimeout(resolve,900) testen.
  4. Nach Bug-Fix: erneut browser_navigate mit Cache-Buster-Query (?fresh=N), sonst serviert der Browser die alte Datei.

Pitfalls

  • KEINE automatische Board/Camera-Rotation, wenn die Seite interaktiv/spielbar sein muss — das permanente Drehen macht Klicks unberechenbar ("wegen der Drehung unspielbar"). Board still; 3D-Wirkung kommt von statischer Kamera + Stein-Platzier-Animationen.
  • 2D-Symbole statt echtes 3D enttäuschen: Nutzer will "echtes 3D" der Steine, nicht nur flache Symbole mit Schatten. Wenn "3D-Grafiken" gewünscht sind, echte Geometrie (MeshPhysicalMaterial, extrudierte Balken, Torus) rendern — nicht CSS-Schatten vortäuschen.
  • browser_console-Expression soll klein bleiben (große Rückgaben → Stream-Timeout). Fehler isoliert in kleinen (function(){})()-Aufrufen zurückgeben.
  • Wenn Three.js nicht mehr gebraucht wird (z.B. Wechsel auf reines 2D-Grid), lib/ entfernen — tote Datei nicht hinterlassen.
  • chown -R www-data:www-data html/ nach dem Schreiben, sonst 403/okay nginx.
  • Aufräumen: PocketBase-Tests (POST) sauber löschen (kein Test-Artefakt im echten Konto).