(() => { const CONVERSATION = [ { a: "Can I register at the venue, or do I need to have registered online?", b: "Walk-in registration is open today! Just bring a valid photo ID and we'll get you set up in minutes.", }, { a: "What if I don't have a confirmation email?", b: "No problem — we can look you up by name at the counter.", }, { a: "Where's the registration counter?", b: "North Atrium, ground floor — straight ahead from the main entrance, past the coffee stand.", }, { a: "How far is that from the main entrance?", b: "About a 2-minute walk — signs are posted the whole way.", }, { a: "Is there parking nearby?", b: "Yes, Lot B is right outside — free for attendees.", }, { a: "Perfect, thank you!", b: "Anytime! Enjoy the event 🎉", }, ]; const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); function initChatDemo() { const widget = document.querySelector(".chat-widget"); if (!widget || !window.gsap) return; const messages = widget.querySelector(".chat-messages"); const textarea = widget.querySelector(".chat-input-bar textarea"); const sendBtn = widget.querySelector(".send-btn"); const status = widget.querySelector(".chat-header .status"); if (!messages || !textarea || !sendBtn || !status) return; // Normalize avatar defs ids const defs = widget.querySelector(".avatar-defs"); let avatarId = "demo"; if (defs) { const groups = defs.querySelectorAll("g[id]"); groups.forEach((g) => { if (g.id.startsWith("avatar-a")) g.id = "avatar-a-demo"; if (g.id.startsWith("avatar-b")) g.id = "avatar-b-demo"; }); } let stopped = false; const timelines = []; const track = (tl) => { timelines.push(tl); tl.eventCallback("onComplete", () => { const i = timelines.indexOf(tl); if (i >= 0) timelines.splice(i, 1); }); return tl; }; const scrollBottom = () => { messages.scrollTop = messages.scrollHeight; }; const avatarSvg = (who) => ``; const resizeInput = () => { textarea.style.height = "auto"; textarea.style.height = `${textarea.scrollHeight}px`; }; const typeIntoInput = (text, speed = 45) => new Promise((resolve) => { textarea.value = ""; resizeInput(); let i = 0; const id = setInterval(() => { if (stopped) { clearInterval(id); resolve(); return; } textarea.value += text[i]; resizeInput(); i += 1; if (i >= text.length) { clearInterval(id); resolve(); } }, speed); }); const addMessage = (who, text) => { const row = document.createElement("div"); row.className = `msg-row from-${who}`; row.innerHTML = `${avatarSvg(who)}
${text}
`; messages.appendChild(row); scrollBottom(); window.gsap.fromTo( row, { opacity: 0, y: 12, scale: 0.96 }, { opacity: 1, y: 0, scale: 1, duration: 0.35, ease: "back.out(1.6)" } ); }; const showTyping = (who) => { const row = document.createElement("div"); row.className = `msg-row from-${who} typing-row`; row.innerHTML = `${avatarSvg(who)}
`; messages.appendChild(row); scrollBottom(); window.gsap.fromTo(row, { opacity: 0 }, { opacity: 1, duration: 0.2 }); const dots = row.querySelectorAll(".dot"); const tl = track(window.gsap.timeline({ repeat: -1 })); tl.to(dots, { y: -5, duration: 0.28, stagger: 0.12, ease: "sine.inOut", yoyo: true, repeat: 1, }).to({}, { duration: 0.15 }); return { remove: () => { tl.kill(); const i = timelines.indexOf(tl); if (i >= 0) timelines.splice(i, 1); window.gsap.to(row, { opacity: 0, duration: 0.15, onComplete: () => row.remove(), }); }, }; }; const pressSend = () => track( window.gsap .timeline() .to(sendBtn, { scale: 0.85, duration: 0.09, ease: "power1.out" }) .to(sendBtn, { scale: 1, duration: 0.18, ease: "back.out(3)" }) ); (async () => { while (!stopped) { messages.innerHTML = ""; textarea.value = ""; textarea.style.height = "auto"; status.textContent = "online"; for (const turn of CONVERSATION) { if (stopped) return; await typeIntoInput(turn.a); if (stopped) return; await sleep(400); if (stopped) return; pressSend(); await sleep(150); if (stopped) return; textarea.value = ""; textarea.style.height = "auto"; addMessage("a", turn.a); await sleep(300); if (stopped) return; status.textContent = "typing…"; const typing = showTyping("b"); await sleep(1300 + 400 * Math.random()); if (stopped) { typing.remove(); return; } typing.remove(); await sleep(200); if (stopped) return; status.textContent = "online"; addMessage("b", turn.b); await sleep(900); } await sleep(1600); } })(); window.addEventListener( "pagehide", () => { stopped = true; timelines.forEach((tl) => tl.kill()); window.gsap.killTweensOf([sendBtn, messages]); }, { once: true } ); } function initFlowDiagram() { const root = document.querySelector(".eb-flow-v3"); if (!root || !window.gsap) return; const beamLength = 80; const prepare = (selector) => { const path = root.querySelector(selector); if (!path) return null; const totalLength = path.getTotalLength(); window.gsap.set(path, { strokeDasharray: `${beamLength} ${totalLength + beamLength}`, strokeDashoffset: beamLength, opacity: 0, }); return { path, totalLength, beamLength }; }; const paths = { step1_1: prepare("#glow-input-to-ai"), step1_2: prepare("#glow-ai-to-middle"), revReg: prepare("#glow-register-to-middle"), revAge: prepare("#glow-agenda-to-middle"), revChk: prepare("#glow-check-in-to-middle"), revEng: prepare("#glow-engagement-to-middle"), middleToAi: prepare("#glow-middle-to-ai"), aiToInput: prepare("#glow-ai-to-input"), }; if (Object.values(paths).some((p) => !p)) return; const animatePath = (item, duration = 1) => window.gsap .timeline() .set(item.path, { opacity: 1, strokeDashoffset: item.beamLength }) .to(item.path, { strokeDashoffset: -item.totalLength, duration, ease: "power1.inOut", }) .set(item.path, { opacity: 0 }); const glowBoxes = (selectors, hold = 0.4, cls = "box-glow") => { const els = (Array.isArray(selectors) ? selectors : [selectors]) .map((s) => root.querySelector(s)) .filter(Boolean); return window.gsap .timeline() .to(els, { onStart: () => els.forEach((el) => el.classList.add(cls)), duration: 0.1, }) .to({}, { duration: hold }) .to(els, { onComplete: () => els.forEach((el) => el.classList.remove(cls)), duration: 0.4, }); }; const phone = root.querySelector("#phone"); if (!phone) return; const middleBoxes = [ "#middle-container", "#intelligence-box", "#context-box", "#intent-box", ]; const tl = window.gsap.timeline({ repeat: -1, repeatDelay: 0.5 }); tl.to(phone, { onStart: () => phone.classList.add("phone-glow-orange"), duration: 0.1, }) .to({}, { duration: 0.4 }) .to(phone, { onStart: () => phone.classList.remove("phone-glow-orange"), duration: 0.4, }) .add(animatePath(paths.step1_1, 1.2), "-=0.2") .add(glowBoxes("#eventbuzz-ai-box", 0.5), "-=0.2") .add(animatePath(paths.step1_2, 1), "-=0.3") .add(glowBoxes(middleBoxes, 0.5), "-=0.2") .add(glowBoxes("#register-box", 0.3, "box-glow-green")) .add(animatePath(paths.revReg, 0.9), "-=0.2") .add(glowBoxes("#agenda-box", 0.3, "box-glow-green")) .add(animatePath(paths.revAge, 0.9), "-=0.2") .add(glowBoxes("#check-in-box", 0.3, "box-glow-green")) .add(animatePath(paths.revChk, 0.9), "-=0.2") .add(glowBoxes("#engagement-box", 0.3, "box-glow-green")) .add(animatePath(paths.revEng, 0.9), "-=0.2") .add(glowBoxes(middleBoxes, 0.5, "box-glow-green"), "-=0.2") .add(animatePath(paths.middleToAi, 0.8)) .add(glowBoxes("#eventbuzz-ai-box", 0.5, "box-glow-green"), "-=0.2") .add(animatePath(paths.aiToInput, 1)) .to( phone, { onStart: () => phone.classList.add("phone-glow-green"), duration: 0.1, }, "-=0.1" ) .to({}, { duration: 2.5 }) .to(phone, { onStart: () => phone.classList.remove("phone-glow-green"), duration: 0.4, }); window.addEventListener( "pagehide", () => { tl.kill(); window.gsap.killTweensOf(root.querySelectorAll("path, rect, g")); phone.classList.remove("phone-glow-orange", "phone-glow-green"); root .querySelectorAll(".box-glow, .box-glow-green") .forEach((el) => el.classList.remove("box-glow", "box-glow-green")); }, { once: true } ); } document.addEventListener("DOMContentLoaded", () => { initChatDemo(); initFlowDiagram(); }); })();