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
This commit is contained in:
Alexander Whitestone
2026-04-10 15:20:48 -04:00
parent f948ec9c5e
commit 41de4e024c
2 changed files with 91 additions and 0 deletions

67
game.js
View File

@@ -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';
}
});