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();

    }


})();

Popular posts from this blog

Effort and Salvation

Wearing Makeup -- Related Quotes from Bible and EGW Writings

Sabbath Cooking Excuses Investigated