Update color palette and styles across components for improved visual consistency

- Changed theme color in index.html to a brighter orange for better aesthetics.
- Introduced a modern color palette in styles.scss for enhanced readability and consistency.
- Updated various components (AppFooter, AppNavigation, DialogWidget, etc.) to utilize new color variables, ensuring a cohesive look throughout the application.
- Adjusted button styles and hover effects for improved user interaction feedback.
- Enhanced background colors and text colors for better contrast and visibility.
This commit is contained in:
Torsten Schulz (local)
2026-01-22 12:22:05 +01:00
parent 41106ae306
commit 78d43e6859
17 changed files with 172 additions and 112 deletions

View File

@@ -3,6 +3,7 @@
</template>
<script>
import { markRaw } from 'vue';
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
@@ -30,7 +31,8 @@ export default {
model: null,
animationId: null,
mixer: null,
clock: new THREE.Clock()
clock: markRaw(new THREE.Clock()),
baseYPosition: 0 // Basis-Y-Position für Animation
};
},
computed: {
@@ -50,8 +52,16 @@ export default {
}
// Zufällige Auswahl beim ersten Mount, dann persistent
if (this.randomAge === null) {
// Zufälliges Alter zwischen 18 und 65 Jahren
this.randomAge = Math.floor(Math.random() * 47) + 18;
// Zufällige Altersgruppe auswählen, damit verschiedene Altersbereiche dargestellt werden
const ageGroups = [
{ min: 0, max: 3 }, // toddler
{ min: 4, max: 7 }, // child
{ min: 8, max: 12 }, // preteen
{ min: 13, max: 17 }, // teen
{ min: 18, max: 65 } // adult
];
const selectedGroup = ageGroups[Math.floor(Math.random() * ageGroups.length)];
this.randomAge = Math.floor(Math.random() * (selectedGroup.max - selectedGroup.min + 1)) + selectedGroup.min;
}
return this.randomAge;
},
@@ -95,39 +105,76 @@ export default {
const container = this.$refs.container;
if (!container) return;
// Scene erstellen
this.scene = new THREE.Scene();
// Scene erstellen - markRaw verwenden, um Vue's Reactivity zu vermeiden
this.scene = markRaw(new THREE.Scene());
// Hintergrund wird später geladen
this.scene.background = new THREE.Color(0xf0f0f0);
// Hintergrundbild laden
this.loadBackground();
// Camera erstellen
const aspect = container.clientWidth / container.clientHeight;
this.camera = new THREE.PerspectiveCamera(50, aspect, 0.1, 1000);
this.camera = markRaw(new THREE.PerspectiveCamera(50, aspect, 0.1, 1000));
this.camera.position.set(0, 1.5, 3);
this.camera.lookAt(0, 1, 0);
// Renderer erstellen
this.renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
this.renderer = markRaw(new THREE.WebGLRenderer({ antialias: true, alpha: true }));
this.renderer.setSize(container.clientWidth, container.clientHeight);
this.renderer.setPixelRatio(window.devicePixelRatio);
container.appendChild(this.renderer.domElement);
// Licht hinzufügen
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
// Verbesserte Beleuchtung für hellere Modelle
// Mehr ambient light für gleichmäßigere Ausleuchtung
const ambientLight = new THREE.AmbientLight(0xffffff, 1.0);
this.scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
// Hauptlicht von vorne oben - stärker
const directionalLight = new THREE.DirectionalLight(0xffffff, 1.2);
directionalLight.position.set(5, 10, 5);
this.scene.add(directionalLight);
// Zusätzliches Licht von hinten
const backLight = new THREE.DirectionalLight(0xffffff, 0.3);
backLight.position.set(-5, 0, -5);
// Zusätzliches Licht von hinten - heller
const backLight = new THREE.DirectionalLight(0xffffff, 0.75);
backLight.position.set(-5, 5, -5);
this.scene.add(backLight);
// Zusätzliches Seitenlicht für mehr Tiefe
const sideLight = new THREE.DirectionalLight(0xffffff, 0.5);
sideLight.position.set(-5, 5, 5);
this.scene.add(sideLight);
// Resize Handler
window.addEventListener('resize', this.onWindowResize);
},
loadBackground() {
// Zufällig einen Hintergrund auswählen
const backgrounds = ['bg1.png', 'bg2.png'];
const randomBg = backgrounds[Math.floor(Math.random() * backgrounds.length)];
const bgPath = `/images/falukant/backgrounds/${randomBg}`;
const loader = new THREE.TextureLoader();
loader.load(
bgPath,
(texture) => {
// Hintergrund erfolgreich geladen
if (this.scene) {
this.scene.background = texture;
}
},
undefined,
(error) => {
console.warn('Fehler beim Laden des Hintergrunds:', error);
// Fallback auf Standardfarbe bei Fehler
if (this.scene) {
this.scene.background = new THREE.Color(0xf0f0f0);
}
}
);
},
async loadModel() {
if (!this.scene) return;
@@ -167,51 +214,57 @@ export default {
gltf = await loader.loadAsync(fallbackPath);
}
this.model = gltf.scene;
// Modell als raw markieren, um Vue's Reactivity zu vermeiden
this.model = markRaw(gltf.scene);
// Modell zentrieren und skalieren
const box = new THREE.Box3().setFromObject(this.model);
const center = box.getCenter(new THREE.Vector3());
const size = box.getSize(new THREE.Vector3());
// Initiale Bounding Box für Größenberechnung (vor Skalierung)
const initialBox = new THREE.Box3().setFromObject(this.model);
const initialSize = initialBox.getSize(new THREE.Vector3());
// Skalierung basierend auf Alter
const age = this.actualAge;
let scale = 1;
let ageScale = 1;
if (age <= 3) {
scale = 0.4;
ageScale = 0.4;
} else if (age <= 7) {
scale = 0.6;
ageScale = 0.6;
} else if (age <= 12) {
scale = 0.75;
ageScale = 0.75;
} else if (age <= 17) {
scale = 0.9;
ageScale = 0.9;
} else {
scale = 1.0;
ageScale = 1.0;
}
// Modell skalieren, damit es in die Szene passt
const maxDimension = Math.max(size.x, size.y, size.z);
const maxDimension = Math.max(initialSize.x, initialSize.y, initialSize.z);
const targetHeight = 2; // Zielhöhe in 3D-Einheiten
const modelScale = (targetHeight / maxDimension) * scale;
const modelScale = (targetHeight / maxDimension) * ageScale;
this.model.scale.set(modelScale, modelScale, modelScale);
// Modell zentrieren
this.model.position.sub(center.multiplyScalar(modelScale));
this.model.position.y = 0; // Auf Boden setzen
// Bounding Box NACH dem Skalieren neu berechnen
const scaledBox = new THREE.Box3().setFromObject(this.model);
const scaledCenter = scaledBox.getCenter(new THREE.Vector3());
// Modell zentrieren basierend auf der skalierten Bounding Box
// Position direkt setzen statt zu subtrahieren, um Proxy-Probleme zu vermeiden
const baseY = -scaledBox.min.y; // Auf Boden setzen (y=0 entspricht dem unteren Rand)
this.model.position.set(-scaledCenter.x, baseY, -scaledCenter.z);
this.baseYPosition = baseY; // Basisposition für Animation speichern
this.scene.add(this.model);
// Animationen laden falls vorhanden
if (gltf.animations && gltf.animations.length > 0) {
this.mixer = new THREE.AnimationMixer(this.model);
this.mixer = markRaw(new THREE.AnimationMixer(this.model));
gltf.animations.forEach((clip) => {
this.mixer.clipAction(clip).play();
});
}
// Sanfte Rotation-Animation
// Keine Rotation - Figuren bleiben statisch
if (this.model) {
this.model.rotation.y = Math.random() * Math.PI * 2;
this.model.rotation.y = 0;
}
} catch (error) {
console.error('Error loading 3D model:', error);
@@ -228,13 +281,7 @@ export default {
this.mixer.update(delta);
}
if (this.model) {
// Sanfte Rotation
this.model.rotation.y += 0.005;
// Sanftes Auf und Ab
this.model.position.y = Math.sin(Date.now() * 0.001) * 0.1;
}
// Keine Bewegung - Modelle bleiben statisch
if (this.renderer && this.scene && this.camera) {
this.renderer.render(this.scene, this.camera);