From 41de4e024c96bcb805290c8a93d1144f7c761138 Mon Sep 17 00:00:00 2001 From: Alexander Whitestone Date: Fri, 10 Apr 2026 15:20:48 -0400 Subject: [PATCH] burn: add export/import save and keyboard shortcut help overlay (#47) - Export button copies save JSON to clipboard - Import button prompts for pasted save data, validates, and reloads - Press ? to toggle hotkey overlay showing all keyboard shortcuts - Press Escape to close the overlay - Styling matches the existing cyber-monastic aesthetic --- game.js | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ index.html | 24 +++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/game.js b/game.js index 920a823..6589cfa 100644 --- a/game.js +++ b/game.js @@ -2131,6 +2131,65 @@ function saveGame() { showSaveToast(); } + +// === EXPORT / IMPORT === +function exportSave() { + const raw = localStorage.getItem('the-beacon-v2'); + if (!raw) { log('No save data to export.'); return; } + navigator.clipboard.writeText(raw).then(() => { + log('Save data copied to clipboard.'); + showExportToast('Save copied to clipboard'); + }).catch(() => { + // Fallback: select in a temporary textarea + const ta = document.createElement('textarea'); + ta.value = raw; + document.body.appendChild(ta); + ta.select(); + document.execCommand('copy'); + document.body.removeChild(ta); + log('Save data copied to clipboard (fallback).'); + showExportToast('Save copied to clipboard'); + }); +} + +function importSave() { + const input = prompt('Paste save data:'); + if (!input || !input.trim()) return; + try { + const data = JSON.parse(input.trim()); + // Validate: must have expected keys + if (typeof data.code !== 'number' || typeof data.phase !== 'number') { + log('Invalid save data: missing required fields.'); + return; + } + localStorage.setItem('the-beacon-v2', input.trim()); + log('Save data imported. Reloading...'); + showExportToast('Save imported — reloading'); + setTimeout(() => location.reload(), 800); + } catch (e) { + log('Invalid save data: not valid JSON.'); + } +} + +function showExportToast(msg) { + const el = document.getElementById('save-toast'); + if (!el) return; + el.textContent = msg; + el.style.display = 'block'; + requestAnimationFrame(() => { el.style.opacity = '1'; }); + setTimeout(() => { + el.style.opacity = '0'; + setTimeout(() => { el.style.display = 'none'; }, 500); + }, 2000); +} + +function toggleHotkeyHelp() { + const el = document.getElementById('hotkey-overlay'); + if (!el) return; + el.style.display = el.style.display === 'flex' ? 'none' : 'flex'; +} + + function loadGame() { const raw = localStorage.getItem('the-beacon-v2'); if (!raw) return false; @@ -2308,4 +2367,12 @@ window.addEventListener('keydown', function (e) { else setBuyAmount(1); } if (e.code === 'KeyS') activateSprint(); + if (e.code === 'Slash' && e.shiftKey) { + e.preventDefault(); + toggleHotkeyHelp(); + } + if (e.code === 'Escape') { + const el = document.getElementById('hotkey-overlay'); + if (el) el.style.display = 'none'; + } }); diff --git a/index.html b/index.html index 549edac..7819453 100644 --- a/index.html +++ b/index.html @@ -131,6 +131,11 @@ body{background:var(--bg);color:var(--text);font-family:'SF Mono','Cascadia Code +
+ + +
+

BUILDINGS

@@ -189,5 +194,24 @@ The light is on. The room is empty." +