diff --git a/node/server/public/app.js b/node/server/public/app.js
index 681cb3f..6721e3c 100644
--- a/node/server/public/app.js
+++ b/node/server/public/app.js
@@ -307,7 +307,6 @@ class Spirit {
this.spiritMeshes.push(mesh);
}
});
- this._setupPicking();
this.scene.add(this.grp);
}
@@ -358,15 +357,6 @@ class Spirit {
}
});
}
-
- _setupPicking() {
- // Hier ein einfacher Ansatz: Mesh mit Info-Objekt merken!
- this.gltf.traverse(mesh => {
- if (mesh.isMesh) {
- mesh.userData._spiritInfo = this.info;
- }
- });
- }
}
// ---- Szene initialisieren ----
@@ -418,249 +408,33 @@ async function spawnSpirit(spiritData) {
const { scene: gltfScene } = await gltfLoader.loadAsync(modelUrl);
const spirit = new Spirit(scene, gltfScene, spiritData, spawnPos);
activeSpirits.push(spirit);
- //updateSpiritOverlay(spiritData);
+ updateSpiritOverlay(spiritData);
}
-// ---- Overlay-Logik ----
-let lastOverlaySpiritData = null;
-
-// Overlay zentriert in der Mitte mit Schließen-X
-function showSpiritOverlay(spirit) {
+// ---- Overlay für Spirit-Infos ----
+function updateSpiritOverlay(spirit) {
let el = document.getElementById('spirit-info');
if (!el) {
el = document.createElement('div');
el.id = 'spirit-info';
el.style = `
- position: fixed;
- left: 50%; top: 50%;
- transform: translate(-50%,-50%);
- color: white;
- background: rgba(0,0,0,0.87);
- padding: 24px 32px 20px 32px;
- border-radius: 16px;
- font-family: 'Segoe UI', sans-serif;
- z-index: 9999;
- max-width: 540px;
- min-width: 300px;
- box-shadow: 0 6px 48px #000a;
- text-align: left;
+ position:absolute; right:40px; bottom:40px; color:white;
+ background:rgba(0,0,0,0.6); padding:10px 18px; border-radius:10px;
+ font-family: sans-serif; z-index:10; max-width: 360px;
`;
document.body.appendChild(el);
}
-
- // --- Canvas-Container ---
el.innerHTML = `
-
-
-
-
- ${spirit.Name || 'Spirit'}
- ${spirit.Kategorie || ''}
- Mythos: ${spirit["Mythos/Legende"] || ''}
- Rolle: ${spirit["Funktion/Rolle"] || ''}
- Charakter: ${spirit.Charakter || ''}
- ${spirit.Herkunft ? '' + spirit.Herkunft + '' : ''}
+ ${spirit.Name || 'Spirit'}
+ ${spirit.Kategorie || ''}
+ Mythos: ${spirit["Mythos/Legende"] || ''}
+ Rolle: ${spirit["Funktion/Rolle"] || ''}
+ Charakter: ${spirit.Charakter || ''}
+ ${spirit.Herkunft ? ' ' + spirit.Herkunft : ''}
+
`;
- el.style.display = "block";
- lastOverlaySpiritData = spirit;
-
- el.querySelector("#spirit-overlay-close").onclick = () => {
- el.style.display = "none";
- destroySpiritModelPreview();
- };
-
- // Lade das Model neu für die Vorschau:
- setupSpiritModelPreview(spirit);
-
}
-let spiritPreviewRenderer = null, spiritPreviewScene = null, spiritPreviewCamera = null, spiritPreviewObj = null;
-let spiritPreviewDragging = false, spiritPreviewLastX = 0, spiritPreviewRotationY = 0, spiritPreviewRotationX = 0;
-
-function destroySpiritModelPreview() {
- // Cleanup: Renderer und Scene entsorgen
- if (spiritPreviewRenderer) {
- spiritPreviewRenderer.dispose();
- spiritPreviewRenderer.domElement.remove();
- spiritPreviewRenderer = null;
- }
- spiritPreviewScene = null;
- spiritPreviewCamera = null;
- spiritPreviewObj = null;
- spiritPreviewDragging = false;
- spiritPreviewLastX = 0;
- spiritPreviewRotationY = 0;
- spiritPreviewRotationX = 0;
-}
-
-async function setupSpiritModelPreview(spirit) {
- destroySpiritModelPreview();
-
- // Canvas erzeugen
- const container = document.getElementById('spirit-model-preview');
- if (!container) return;
- const width = container.clientWidth;
- const height = container.clientHeight;
-
- // Three.js Preview Renderer
- spiritPreviewRenderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
- spiritPreviewRenderer.setClearColor(0x000000, 0); // transparent
- spiritPreviewRenderer.setSize(width, height, false);
- container.appendChild(spiritPreviewRenderer.domElement);
-
- // Preview Szene und Kamera
- spiritPreviewScene = new THREE.Scene();
- spiritPreviewCamera = new THREE.PerspectiveCamera(27, width / height, 0.1, 100);
- spiritPreviewCamera.position.set(0, 1, 5);
-
- // Licht
- const keyLight = new THREE.DirectionalLight(0xffffff, 1.2);
- keyLight.position.set(3, 4, 8);
- spiritPreviewScene.add(keyLight);
- const fillLight = new THREE.AmbientLight(0xffffff, 0.85);
- spiritPreviewScene.add(fillLight);
-
- // Model laden
- const modelUrl = spirit['Model URL'] || spirit.modelUrl;
- try {
- const { scene: modelObj } = await gltfLoader.loadAsync(modelUrl);
- // Färbe/Resette ggf. Materialien (optional, nicht zwingend nötig)
- modelObj.traverse(mesh => {
- if (mesh.isMesh) {
- mesh.castShadow = false;
- mesh.receiveShadow = false;
- mesh.material = mesh.material.clone();
- mesh.material.opacity = 1.0;
- mesh.material.transparent = false;
- mesh.material.emissiveIntensity = 1.0;
- }
- });
- // Zentriere das Modell (Bounding Box)
- const bbox = new THREE.Box3().setFromObject(modelObj);
- const center = bbox.getCenter(new THREE.Vector3());
- modelObj.position.sub(center);
- // Größe skalieren
- const size = bbox.getSize(new THREE.Vector3());
- const maxDim = Math.max(size.x, size.y, size.z);
- const scale = 2.1 / maxDim;
- modelObj.scale.setScalar(scale);
-
- // Initiale Drehung: leicht nach rechts & von oben
- spiritPreviewRotationY = Math.PI / 8;
- spiritPreviewRotationX = -Math.PI / 18;
- modelObj.rotation.y = spiritPreviewRotationY;
- modelObj.rotation.x = spiritPreviewRotationX;
-
- spiritPreviewObj = modelObj;
- spiritPreviewScene.add(modelObj);
- } catch (err) {
- container.innerHTML = `Modell konnte nicht geladen werden :(
`;
- return;
- }
-
- // Maus-Events für Drehung
- const canvas = spiritPreviewRenderer.domElement;
- canvas.style.cursor = "grab";
- canvas.onpointerdown = (e) => {
- spiritPreviewDragging = true;
- spiritPreviewLastX = e.clientX;
- canvas.setPointerCapture(e.pointerId);
- canvas.style.cursor = "grabbing";
- };
- canvas.onpointermove = (e) => {
- if (spiritPreviewDragging && spiritPreviewObj) {
- let delta = (e.clientX - spiritPreviewLastX) / width * Math.PI;
- spiritPreviewRotationY += delta;
- spiritPreviewObj.rotation.y = spiritPreviewRotationY;
- spiritPreviewLastX = e.clientX;
- }
- };
- canvas.onpointerup = (e) => {
- spiritPreviewDragging = false;
- canvas.releasePointerCapture(e.pointerId);
- canvas.style.cursor = "grab";
- };
-
- // Vertikales Drag: Optional für X-Rotation
- let lastY = 0;
- canvas.onpointerdown = (e) => {
- spiritPreviewDragging = true;
- spiritPreviewLastX = e.clientX;
- lastY = e.clientY;
- canvas.setPointerCapture(e.pointerId);
- canvas.style.cursor = "grabbing";
- };
- canvas.onpointermove = (e) => {
- if (spiritPreviewDragging && spiritPreviewObj) {
- let deltaX = (e.clientX - spiritPreviewLastX) / width * Math.PI;
- let deltaY = (e.clientY - lastY) / height * Math.PI;
- spiritPreviewRotationY += deltaX;
- spiritPreviewRotationX += deltaY;
- spiritPreviewRotationX = Math.max(-Math.PI / 2.3, Math.min(Math.PI / 2.3, spiritPreviewRotationX)); // Limitiere X
- spiritPreviewObj.rotation.y = spiritPreviewRotationY;
- spiritPreviewObj.rotation.x = spiritPreviewRotationX;
- spiritPreviewLastX = e.clientX;
- lastY = e.clientY;
- }
- };
- canvas.onpointerup = (e) => {
- spiritPreviewDragging = false;
- canvas.releasePointerCapture(e.pointerId);
- canvas.style.cursor = "grab";
- };
-
- // Animation/Rendering starten
- previewRenderLoop();
-}
-
-function previewRenderLoop() {
- if (!spiritPreviewRenderer || !spiritPreviewScene || !spiritPreviewCamera) return;
- spiritPreviewRenderer.render(spiritPreviewScene, spiritPreviewCamera);
- // Nur weiter machen, wenn das Overlay sichtbar ist!
- let el = document.getElementById('spirit-info');
- if (el && el.style.display !== 'none') {
- requestAnimationFrame(previewRenderLoop);
- }
-}
-
-// Mouse-Picking (zentral)
-const raycaster = new THREE.Raycaster();
-const mouse = new THREE.Vector2();
-
-function onClick(e) {
- // Normierte Koordinaten im WebGL-Fenster:
- const rect = renderer.domElement.getBoundingClientRect();
- mouse.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
- mouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
-
- raycaster.setFromCamera(mouse, camera);
- // Sammle alle Meshes aus allen aktiven Spirits
- let allMeshes = [];
- for (const spirit of activeSpirits) {
- spirit.gltf.traverse(mesh => {
- if (mesh.isMesh) allMeshes.push(mesh);
- });
- }
- const intersects = raycaster.intersectObjects(allMeshes, false);
- if (intersects.length > 0) {
- const mesh = intersects[0].object;
- if (mesh.userData._spiritInfo) {
- showSpiritOverlay(mesh.userData._spiritInfo);
- }
- }
-}
-
-// Fügt das Event hinzu:
-renderer.domElement.addEventListener('pointerdown', onClick);
-
-// Kein automatisches Update mehr! Nicht von spawnSpirit aufrufen!
-// (aber Option: „verstecke Overlay“ falls Spirit verschwindet, kann man so machen...)
-
// ---- Render-Loop ----
function animate() {
const dt = clock.getDelta(), t = clock.getElapsedTime();
@@ -676,11 +450,4 @@ function animate() {
composer.render(scene, camera);
requestAnimationFrame(animate);
-}
-
-document.addEventListener('keydown', (e) => {
- if (e.key === 'Escape') {
- let el = document.getElementById('spirit-info');
- if (el) el.style.display = "none";
- }
-});
\ No newline at end of file
+}
\ No newline at end of file