Files
brabetz-homepage/src/components/SubpageRain.astro
T

185 lines
9.8 KiB
Plaintext

---
// src/components/SubpageRain.astro
---
<script is:inline>
window.rainData = function() {
return {
rainIntensity: 50,
wind: 0,
lofiFilter: 800,
musicVolume: 30,
drops: [],
audioCtx: null,
noiseNode: null,
filterNode: null,
gainNode: null,
melodyGain: null,
generateDrops(val) {
this.drops = [];
for(let i=0; i<val; i++) this.drops.push({ left: Math.random()*100, speed: 0.5+Math.random()*0.5, delay: Math.random()*2 });
},
initAudio() {
if (this.audioCtx) return;
try {
this.audioCtx = new (window.AudioContext || window.webkitAudioContext)();
// --- REGEN-SOUND (Weißes Rauschen) ---
let bufferSize = 2 * this.audioCtx.sampleRate;
let noiseBuffer = this.audioCtx.createBuffer(1, bufferSize, this.audioCtx.sampleRate);
let output = noiseBuffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) {
output[i] = Math.random() * 2 - 1;
}
this.noiseNode = this.audioCtx.createBufferSource();
this.noiseNode.buffer = noiseBuffer;
this.noiseNode.loop = true;
this.filterNode = this.audioCtx.createBiquadFilter();
this.filterNode.type = 'lowpass';
this.filterNode.frequency.setValueAtTime(this.lofiFilter, this.audioCtx.currentTime);
this.gainNode = this.audioCtx.createGain();
this.gainNode.gain.setValueAtTime(this.rainIntensity / 200 * 0.05, this.audioCtx.currentTime);
this.noiseNode.connect(this.filterNode);
this.filterNode.connect(this.gainNode);
this.gainNode.connect(this.audioCtx.destination);
this.noiseNode.start();
// --- MELODIE-SOUND (Echte "Easy Music") ---
let melodyOsc = this.audioCtx.createOscillator();
this.melodyGain = this.audioCtx.createGain();
melodyOsc.type = 'sine';
let lowpass = this.audioCtx.createBiquadFilter();
lowpass.type = 'lowpass';
lowpass.frequency.setValueAtTime(400, this.audioCtx.currentTime); // Sehr dumpf und weich
melodyOsc.connect(lowpass);
lowpass.connect(this.melodyGain);
this.melodyGain.connect(this.audioCtx.destination);
melodyOsc.start();
// Langsame, beruhigende Pentatonik-Folge
let notes = [261.63, 329.63, 392.00, 440.00, 392.00, 329.63]; // C4, E4, G4, A4, G4, E4
let i = 0;
setInterval(() => {
let now = this.audioCtx.currentTime;
let freq = notes[i];
melodyOsc.frequency.setValueAtTime(freq, now);
// Sanftes Ein- und Ausblenden der Note
let maxVol = (this.musicVolume / 100) * 0.05;
this.melodyGain.gain.setValueAtTime(0, now);
this.melodyGain.gain.linearRampToValueAtTime(maxVol, now + 1.5);
this.melodyGain.gain.linearRampToValueAtTime(0, now + 3.5);
i = (i + 1) % notes.length;
}, 4000); // Alle 4 Sekunden eine Note
} catch(e) {
console.log('Audio failed', e);
}
},
updateAudio() {
if (this.gainNode) {
this.gainNode.gain.linearRampToValueAtTime(this.rainIntensity / 200 * 0.05, this.audioCtx.currentTime + 0.2);
}
if (this.filterNode) {
this.filterNode.frequency.linearRampToValueAtTime(this.lofiFilter, this.audioCtx.currentTime + 0.2);
}
}
};
}
</script>
<!-- Subpage: Rain Detail -->
<div x-show="currentPage === 'page-rain'" x-cloak x-transition:enter="transition ease-out duration-500" x-transition:enter-start="opacity-0 translate-y-4" x-transition:enter-end="opacity-100 translate-y-0" class="min-h-screen pt-28 pb-24 px-6 lg:px-8 bg-stone-950 relative overflow-hidden"
x-data="window.rainData()"
x-init="generateDrops(rainIntensity); $watch('rainIntensity', value => { generateDrops(value); updateAudio() }); $watch('lofiFilter', value => updateAudio()); $watch('currentPage', val => { if(val === 'page-rain') initAudio(); })">
<!-- Rain Container (Full Screen on this page) -->
<div class="absolute inset-0 pointer-events-none z-0">
<template x-for="drop in drops">
<div class="absolute bg-emerald-400/30 w-0.5 h-8"
:style="`left: ${drop.left}%; top: -20px; animation: fall ${drop.speed}s linear infinite; animation-delay: ${drop.delay}s; transform: rotate(${wind}deg)`">
</div>
</template>
</div>
<div class="max-w-4xl mx-auto space-y-12 relative z-10">
<button @click="currentPage = 'main'" class="text-stone-400 hover:text-white transition-colors font-semibold text-xs uppercase tracking-wider flex items-center gap-2 bg-stone-900 px-5 py-2.5 rounded-lg border border-stone-800 hover:border-stone-700">
<i class="fa-solid fa-arrow-left"></i> Zurück zur Übersicht
</button>
<div class="border-b border-stone-800 pb-6">
<span class="text-xs text-emerald-500 font-mono uppercase tracking-widest block mb-2">Atmosphäre & Ökologie</span>
<h1 class="text-4xl sm:text-5xl font-luxury font-bold text-white">Regen für Gemütlichkeit</h1>
</div>
<!-- Controls -->
<div class="glass p-8 rounded-2xl border border-stone-800 space-y-6">
<!-- Intensity -->
<div>
<label class="block text-xs font-mono text-stone-500 uppercase mb-2 tracking-widest">Regen-Intensität: <span x-text="rainIntensity" class="text-emerald-400"></span> Tropfen</label>
<input type="range" min="0" max="200" x-model="rainIntensity" class="w-full h-2 bg-stone-800 rounded-lg appearance-none cursor-pointer accent-emerald-500">
</div>
<!-- Wind -->
<div>
<label class="block text-xs font-mono text-stone-500 uppercase mb-2 tracking-widest">Windstärke (Neigung): <span x-text="wind" class="text-emerald-400"></span>°</label>
<input type="range" min="-45" max="45" x-model="wind" class="w-full h-2 bg-stone-800 rounded-lg appearance-none cursor-pointer accent-emerald-500">
</div>
<!-- Lofi Filter -->
<div>
<label class="block text-xs font-mono text-stone-500 uppercase mb-2 tracking-widest">Lofi-Filter (Muffigkeit): <span x-text="lofiFilter" class="text-emerald-400"></span> Hz</label>
<input type="range" min="200" max="2000" x-model="lofiFilter" class="w-full h-2 bg-stone-800 rounded-lg appearance-none cursor-pointer accent-emerald-500">
</div>
<!-- Music Volume -->
<div>
<label class="block text-xs font-mono text-stone-500 uppercase mb-2 tracking-widest">Musik-Lautstärke: <span x-text="musicVolume" class="text-emerald-400"></span>%</label>
<input type="range" min="0" max="100" x-model="musicVolume" class="w-full h-2 bg-stone-800 rounded-lg appearance-none cursor-pointer accent-emerald-500">
</div>
<div class="flex justify-between text-xs text-stone-600 font-mono pt-4 border-t border-stone-800">
<span>Sound läuft automatisch</span>
<span class="text-emerald-400">Realtime Web Audio Rain & Melody</span>
</div>
</div>
<!-- YouTube Player -->
<div class="glass p-6 rounded-2xl border border-stone-800 space-y-4">
<div>
<span class="block text-xs font-mono text-stone-500 uppercase mb-1 tracking-widest">Zusatz-Musik</span>
<span class="text-xs text-stone-400">Lofi Hip Hop Groove (YouTube Stream)</span>
</div>
<div class="rounded-lg overflow-hidden border border-stone-800">
<iframe width="100%" height="80" src="https://www.youtube.com/embed/jfKfPfyJRdk" title="Lofi Hip Hop" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</div>
</div>
<!-- Content -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 text-stone-400 text-sm leading-relaxed">
<div class="space-y-4">
<h3 class="text-white font-bold text-lg">Warum wir den Regen lieben</h3>
<p>Für viele ist Regen ein Grund, im Haus zu bleiben. Für uns Gärtner ist er der Herzschlag der Natur. Ohne Regen gibt es kein Wachstum, keine Kühlung und keine Erholung für den Boden.</p>
<p>Mit unserem "Regen-Modus" möchten wir dir die beruhigende Wirkung eines Sommerregens näherbringen. Setz dich hin, dreh die Intensität hoch und genieße die Atmosphäre.</p>
</div>
<div class="space-y-4">
<h3 class="text-white font-bold text-lg">Vom Genuss zur Technik</h3>
<p>Aber Regen ist nicht nur Atmosphäre. In Zeiten des Klimawandels müssen wir lernen, jeden Tropfen zu nutzen. Hier schließt sich der Kreis zu unserem **Schwammstadt-Prinzip**.</p>
<p>Wir bauen Gärten, die das Wasser nicht einfach ableiten, sondern wie ein Schwamm aufsaugen und speichern. So schützen wir vor Überflutung und versorgen die Pflanzen in Trockenzeiten.</p>
</div>
</div>
</div>
</div>