From beee17f43c2c6e4e2f52e8132202aa7d35a0468d Mon Sep 17 00:00:00 2001 From: "Claude (Opus 4.6)" Date: Tue, 24 Mar 2026 04:53:23 +0000 Subject: [PATCH] [claude] Add session export as markdown (#288) (#304) Co-authored-by: Claude (Opus 4.6) Co-committed-by: Claude (Opus 4.6) --- app.js | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ index.html | 3 +++ style.css | 19 ++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/app.js b/app.js index 3ad45ee..e86b38a 100644 --- a/app.js +++ b/app.js @@ -1223,9 +1223,66 @@ window.addEventListener('player-left', (/** @type {CustomEvent} */ event) => { console.log('Player left:', event.detail); }); +// === SESSION EXPORT === +/** @type {{ ts: number, speaker: string, text: string }[]} */ +const sessionLog = []; +const sessionStart = Date.now(); + +/** + * Appends an entry to the in-memory session log. + * @param {string} speaker + * @param {string} text + */ +function logMessage(speaker, text) { + sessionLog.push({ ts: Date.now(), speaker, text }); +} + +/** + * Formats the session log as Markdown and triggers a browser download. + */ +function exportSessionAsMarkdown() { + const startStr = new Date(sessionStart).toISOString().replace('T', ' ').slice(0, 19) + ' UTC'; + const lines = [ + '# Nexus Session Export', + '', + `**Session started:** ${startStr}`, + `**Messages:** ${sessionLog.length}`, + '', + '---', + '', + ]; + + for (const entry of sessionLog) { + const timeStr = new Date(entry.ts).toISOString().replace('T', ' ').slice(0, 19) + ' UTC'; + lines.push(`### ${entry.speaker} — ${timeStr}`); + lines.push(''); + lines.push(entry.text); + lines.push(''); + } + + if (sessionLog.length === 0) { + lines.push('*No messages recorded this session.*'); + lines.push(''); + } + + const blob = new Blob([lines.join('\n')], { type: 'text/markdown' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `nexus-session-${new Date(sessionStart).toISOString().slice(0, 10)}.md`; + a.click(); + URL.revokeObjectURL(url); +} + +const exportBtn = document.getElementById('export-session'); +if (exportBtn) { + exportBtn.addEventListener('click', exportSessionAsMarkdown); +} + window.addEventListener('chat-message', (/** @type {CustomEvent} */ event) => { console.log('Chat message:', event.detail); if (typeof event.detail?.text === 'string') { + logMessage(event.detail.speaker || 'TIMMY', event.detail.text); showTimmySpeech(event.detail.text); if (event.detail.text.toLowerCase().includes('sovereignty')) { triggerSovereigntyEasterEgg(); diff --git a/index.html b/index.html index 69d6b65..73dd69a 100644 --- a/index.html +++ b/index.html @@ -33,6 +33,9 @@ + diff --git a/style.css b/style.css index 8ccbc2d..3dc0e04 100644 --- a/style.css +++ b/style.css @@ -61,6 +61,25 @@ canvas { margin-left: 8px; } +/* === SESSION EXPORT === */ +#export-session { + margin-left: 8px; + background-color: var(--color-secondary); + color: var(--color-text); + padding: 4px 8px; + border: none; + border-radius: 4px; + font-size: 12px; + cursor: pointer; + font-family: var(--font-body); + transition: background-color 0.2s ease; +} + +#export-session:hover { + background-color: var(--color-primary); + color: var(--color-bg); +} + .collision-box { outline: 2px solid red; outline-offset: 2px;