Zum Inhalt springen
/**
* Minimaler, performanter Scramble-Animator ohne Club-Plugin.
* Idee: pro Zeichen einen "Reveal-Timestamp" bestimmen und bis dahin Zufallszeichen rotieren.
*/
(function() {
const RANDOM_CHARS = "!-_\\/[]{}—=+*^?#___________0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
function scrambleTo(el, finalText, duration = 1.2, delay = 0) {
const startTime = performance.now() + (delay * 1000);
const total = Math.max(finalText.length, (el.textContent||'').length);
const from = (el.textContent || '').padEnd(total, ' ');
const to = (finalText || '').padEnd(total, ' ');
const revealTimes = [];
const now = performance.now();
// verteilt die "Aufdeck"-Zeitpunkte pro Zeichen über die Gesamtdauer
for (let i = 0; i < total; i++) {
const pct = i / (total - 1 || 1);
// leicht ungleichmässig, damit es natürlicher wirkt
const jitter = (Math.random() - 0.5) * 0.2;
const t = Math.max(0, Math.min(1, pct + jitter));
revealTimes[i] = t;
}
function frame(t) {
if (t < startTime) {
requestAnimationFrame(frame);
return;
}
const progress = Math.min(1, (t - startTime) / (duration * 1000));
let out = "";
for (let i = 0; i = r) {
out += to[i];
} else {
// solange noch nicht "aufgedeckt": zufälliges Zeichen
out += RANDOM_CHARS[Math.floor(Math.random() * RANDOM_CHARS.length)];
}
}
el.textContent = out;
if (progress {
document.querySelectorAll('.gsap-scramble').forEach((el) => {
const finalText = el.getAttribute('data-text') || el.textContent.trim();
const duration = parseFloat(el.getAttribute('data-duration')) || 2.4;
const delay = parseFloat(el.getAttribute('data-delay')) || 0;
const triggerMode = (el.getAttribute('data-trigger') || 'self').toLowerCase();
// Startzustand: zeigt sofort irgendwas Lesbares (optional leer)
el.textContent = finalText;
// ScrollTrigger einrichten
ScrollTrigger.create({
trigger: triggerMode === 'parent' && el.parentElement ? el.parentElement : el,
start: "top 85%", // beginnt, wenn das Element in den Viewport kommt
once: true, // nur einmal animieren
onEnter: () => {
// vor Start kurz "verrauschen", damit der Effekt sichtbar ist
el.textContent = "".padEnd(finalText.length, ' ');
scrambleTo(el, finalText, duration, delay);
}
});
});
});
})();