BabelRoom

Live chat in any language. Type in yours, read in theirs.

or join an existing room

No login. No account. No data stored.
Messages are transient — close the tab, they're gone.
Built by Tyler McTaggart | CC BY-NC-SA 4.0

BabelRoom

1 online

Participants

EN
Connecting...
'; var blob = new Blob([html], { type: 'text/html;charset=utf-8' }); var url = URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; a.download = 'babelroom-secure-' + roomCode + '-' + new Date().toISOString().slice(0,10) + '.html'; a.click(); setTimeout(function() { URL.revokeObjectURL(url); }, 100); addSystemMessage('Secure document generated (24-hour expiry). Share the HTML file + passphrase separately.'); } // ---- Legal Mode Toggle ---- btnCreateLegal.addEventListener('click', function() { legalOptions.style.display = legalOptions.style.display === 'none' ? 'block' : 'none'; joinPassphraseRow.style.display = legalOptions.style.display === 'none' ? 'none' : 'block'; }); btnCreateLegalRoom.addEventListener('click', async function() { var name = userName.value.trim(); if (!name) { joinError.textContent = 'Enter your name.'; joinError.classList.add('visible'); return; } var passphrase = roomPassphraseInput.value; if (!passphrase || passphrase.length < 4) { joinError.textContent = 'Passphrase must be at least 4 characters.'; joinError.classList.add('visible'); return; } legalMode = true; firmName = firmNameInput.value.trim(); firmWebhook = firmWebhookInput.value.trim(); firmEmail = firmEmailInput.value.trim(); clientEmail = clientEmailInput.value.trim(); var code = generateRoomCode(); encryptionKey = await deriveEncryptionKey(passphrase, 'babelroom-' + code); btnSecureLink.style.display = ''; enterRoom(code); addSystemMessage('Encrypted legal consultation room created. Code: ' + code + ''); addSystemMessage('SOLICITOR-CLIENT PRIVILEGE — This conversation is privileged and confidential. All messages are encrypted (AES-256-GCM). The transcript will be provided to both parties upon session end.'); }); // Update join to handle encrypted rooms var originalBtnJoinHandler = btnJoin.onclick; btnJoin.removeEventListener('click', btnJoin._handler); btnJoin.addEventListener('click', async function() { var code = roomCodeInput.value.trim().toUpperCase().replace(/[^A-Z0-9]/g, ''); if (code.length < 4) { joinError.textContent = 'Enter a valid room code.'; joinError.classList.add('visible'); return; } var name = userName.value.trim(); if (!name) { joinError.textContent = 'Enter your name.'; joinError.classList.add('visible'); return; } var passphrase = joinPassphraseInput.value; if (passphrase) { legalMode = true; encryptionKey = await deriveEncryptionKey(passphrase, 'babelroom-' + code); } joinError.classList.remove('visible'); enterRoom(code); addSystemMessage('Joined room ' + code + '' + (legalMode ? ' (encrypted)' : '')); if (legalMode) { addSystemMessage('SOLICITOR-CLIENT PRIVILEGE — This conversation is privileged and confidential. All messages are encrypted.'); } }); function downloadTranscript() { if (chatLog.length === 0) return; var md = buildTranscriptMD('bilingual'); var dateStr = new Date().toISOString().slice(0, 10); var blob = new Blob([md], { type: 'text/markdown;charset=utf-8' }); var url = URL.createObjectURL(blob); var a = document.createElement('a'); a.href = url; a.download = 'babelroom-transcript-' + roomCode + '-' + dateStr + '.md'; a.click(); setTimeout(function() { URL.revokeObjectURL(url); }, 100); } roomCodeDisplay.addEventListener('click', function() { if (navigator.clipboard) { navigator.clipboard.writeText(roomCode).then(function() { var orig = roomCodeDisplay.textContent; roomCodeDisplay.textContent = 'COPIED'; setTimeout(function() { roomCodeDisplay.textContent = orig; }, 1200); }); } }); // Clean up on close window.addEventListener('beforeunload', function() { if (client && client.connected) { publish({ type: 'leave', id: myId, sender: myName }); client.end(false); } }); })();