/** * Streaming typewriter effect - appends characters to a ref element * @param {string} text - Text to stream * @param {function} onChar - Called with accumulated text on each character * @param {number} delayMs - Delay between characters * @param {AbortSignal} signal - Optional abort signal */ export async function streamText(text, onChar, delayMs = 8, signal = null) { let accumulated = ''; for (const char of text) { if (signal && signal.aborted) break; accumulated += char; onChar(accumulated); await new Promise((r) => setTimeout(r, delayMs)); } return accumulated; }