// WHO AM I tab — info on Karate Wiener, voiced welcome + testimonial gallery + a chat // modal. Tutorial STEP 1: the rail tab pulses on first start until opened. (function () { var TKEY = 'kimodoTutorial'; function load() { try { return JSON.parse(localStorage.getItem(TKEY) || '{}') || {}; } catch (e) { return {}; } } function save(o) { try { localStorage.setItem(TKEY, JSON.stringify(o)); } catch (e) {} } function tab() { return document.getElementById('kimodo-whoami-toggle'); } function setPulse(on) { var t = tab(); if (t) t.classList.toggle('kimodo-whoami-pulse', !!on); } function seen() { return !!load().whoamiSeen; } function applyState() { setPulse(!seen()); } function markSeen() { var o = load(); if (!o.whoamiSeen) { o.whoamiSeen = true; save(o); } setPulse(false); } function whoamiBase() { var b = (typeof DATASET_BASE !== 'undefined' && DATASET_BASE) ? DATASET_BASE : ''; return b + '/viewer/whoami/'; } var TESTIMONIALS = 4; var built = false; var galleryImages = []; // testimonial srcs (lightbox swipes through these) var welcomeBtn = null; // the welcome speak/stop button (right of the hero image) var welcomePlayedThisSession = false; // auto-play the welcome voice only once per page load var topChatBtn = null; // the top-right "tap to chat" shortcut (beside the volume button) // Toggle the loading shimmer on the top-right chat shortcut while a reply (text) or its // voice (TTS) is being generated — mirrors the dojo "generating" overlay. function refreshTopChat() { if (topChatBtn) topChatBtn.classList.toggle('loading', chatBusy || speakActive); } // Top-right chat shortcut so you can talk to Karate Wiener from anywhere (no WHO AM I tab). function installTopChat() { if (document.getElementById('kw-topchat')) return; // On *.hf.space the HF header (like / community / links) lives at the top-right, so push our // floating buttons down below it (see .kw-on-space rules in whoami.tab.css). if (/\.hf\.space$/i.test(location.hostname)) document.documentElement.classList.add('kw-on-space'); topChatBtn = document.createElement('button'); topChatBtn.id = 'kw-topchat'; topChatBtn.className = 'kw-topchat'; topChatBtn.type = 'button'; topChatBtn.title = 'Chat with Karate Wiener'; topChatBtn.innerHTML = '💬'; topChatBtn.addEventListener('click', function () { openChat(); }); document.body.appendChild(topChatBtn); } function buildWhoami() { if (built) return; var base = whoamiBase(); var hero = document.getElementById('kimodo-whoami-hero-img'); if (hero && !hero.getAttribute('src')) hero.src = base + 'weiner.webp'; welcomeBtn = document.getElementById('kimodo-whoami-wspeak'); if (welcomeBtn && !welcomeBtn._wired) { welcomeBtn._wired = true; wireSpeak(welcomeBtn, '', false, base + 'wiener-welcome.wav'); } var gal = document.getElementById('kimodo-whoami-gallery'); if (gal && !gal.childNodes.length) { galleryImages = []; for (var i = 1; i <= TESTIMONIALS; i++) { var src = base + 'testimonial-' + i + '.webp'; galleryImages.push(src); var img = document.createElement('img'); img.src = src; img.alt = 'Student testimonial ' + i; img.loading = 'lazy'; img.addEventListener('click', (function (idx) { return function () { openLightbox(idx); }; })(i - 1)); gal.appendChild(img); } } var chatBtn = document.getElementById('kimodo-whoami-chatbtn'); if (chatBtn && !chatBtn._wired) { chatBtn._wired = true; var av = document.getElementById('kimodo-whoami-chatav'); if (av && !av.getAttribute('src')) av.src = base + 'wiener-meditate.webp'; chatBtn.addEventListener('click', openChat); } built = true; } // ---- Shared voice player --------------------------------------------------- // ONE