ssnet closed captions live (paste the code to developer console) on each tab you're going to use to teach
(function() {
// --- CONFIGURATION ---
const SCROLL_SPEED = 0.1; // 0.1 = smooth/slow, 0.5 = fast, 1.0 = instant
const MAX_CHARS = 500; // Keep text buffer clean
// 1. Check Browser Support
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
if (!SpeechRecognition) {
alert("Web Speech API not supported in this browser.");
return;
}
// 2. Cleanup old instances and old event listeners
const existingBox = document.getElementById('smooth-caption-overlay');
if (existingBox) existingBox.remove();
// Clean up global listeners if this script is pasted multiple times in the same tab
if (window._ccListenersAdded) {
document.removeEventListener("visibilitychange", window._ccVisibility);
window.removeEventListener("blur", window._ccBlur);
window.removeEventListener("focus", window._ccFocus);
}
// 3. Create DOM Elements
const container = document.createElement('div');
container.id = 'smooth-caption-overlay';
container.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100%;
/* 16px font * 1.5 line-height = 24px per line. 2 lines = 48px + 16px padding = 64px */
height: 64px;
padding: 8px 20px;
box-sizing: border-box;
background-color: rgba(0, 0, 0, 0.5);
z-index: 10000;
pointer-events: none;
overflow: hidden;
font-family: 'Segoe UI', sans-serif;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
`;
const scrollWrapper = document.createElement('div');
scrollWrapper.style.cssText = `
width: 100%;
color: white;
font-size: 16px;
line-height: 24px;
font-weight: 600;
text-shadow: 1px 1px 2px #000;
will-change: transform;
word-wrap: break-word;
`;
container.appendChild(scrollWrapper);
document.body.appendChild(container);
// Initial State
let textContent = "Listening...";
scrollWrapper.innerText = textContent;
// 4. Smooth Vertical Scrolling
function animateScroll() {
let targetScroll = container.scrollHeight - container.clientHeight;
if (targetScroll < 0) targetScroll = 0;
let currentScroll = container.scrollTop;
let nextScroll = currentScroll + (targetScroll - currentScroll) * SCROLL_SPEED;
container.scrollTop = nextScroll;
requestAnimationFrame(animateScroll);
}
requestAnimationFrame(animateScroll);
// 5. Setup Speech Recognition
const recognition = new SpeechRecognition();
recognition.continuous = true;
recognition.interimResults = true;
recognition.lang = 'en-US';
recognition.onresult = (event) => {
let fullScript = '';
for (let i = 0; i < event.results.length; ++i) {
fullScript += event.results[i][0].transcript;
}
if (fullScript.length > MAX_CHARS) {
fullScript = "..." + fullScript.substring(fullScript.length - MAX_CHARS);
}
if (scrollWrapper.innerText !== fullScript) {
scrollWrapper.innerText = fullScript;
}
};
recognition.onerror = (e) => console.log("Speech Error:", e.error);
// Auto-restart on silence (ONLY if tab is active)
recognition.onend = () => {
if (isListeningAllowed) {
try { recognition.start(); } catch(e){}
}
};
// --- 6. FOCUS & VISIBILITY MANAGEMENT ---
// Track if the current tab is allowed to use the mic
let isListeningAllowed = !document.hidden;
window._ccVisibility = function() {
if (document.hidden) pauseMic();
else resumeMic();
};
window._ccBlur = function() {
pauseMic();
};
window._ccFocus = function() {
resumeMic();
};
function pauseMic() {
if (!isListeningAllowed) return; // Already paused
isListeningAllowed = false;
recognition.stop();
scrollWrapper.innerText = "[ Paused - Mic Released ]";
console.log("Tab inactive: Mic released.");
}
function resumeMic() {
if (isListeningAllowed || document.hidden) return; // Already listening or still hidden
isListeningAllowed = true;
// Clear text
scrollWrapper.innerText = "Listening...";
console.log("Tab active: Mic resumed.");
try { recognition.start(); } catch(e){}
}
// Attach Focus/Visibility Listeners
document.addEventListener("visibilitychange", window._ccVisibility);
window.addEventListener("blur", window._ccBlur); // Catches clicking away to another app
window.addEventListener("focus", window._ccFocus);
window._ccListenersAdded = true;
// Start immediately if allowed
if (isListeningAllowed) {
recognition.start();
console.log("Smooth Scrolling Captions Active.");
} else {
pauseMic();
}
})();