Deepgrain Foundry: move from a claude.ai artifact to a local repository
The game as of artifact version 24, ready for local development with coding agents. - Source split from three large files into 52 small ones under src/sim, src/render and src/ui, joined in the order in src/manifest.json by build.py. The joined code is unchanged apart from comments; every headless suite gives the same output, and screenshots in both looks are pixel-identical to before. - Light tidying with no change in behaviour: one movement scan loop, shared hazard-stripe and belt shader helpers, unused code removed, a shared check helper for the test suites. - World files can be exported as an ordinary download outside claude.ai. - Tests: broken old scripts removed, experiments moved to tools/, test/run_all.py added. Tools: shot.py (repeatable screenshots), where.py, map.py. - Docs: AGENTS.md, CLAUDE.md, NOTES.md (the owner's to-do inbox), docs/PROJECT_MAP.md, DESIGN.md, TESTING.md, systems notes, the owner's requests and an agent log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01K9kLmYADKSEjuwUN3rFxDA
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
// Starting, loading and quitting a game; modal dialogs; the pause menu.
|
||||
// ---------- Start / stop ----------
|
||||
function showLoading(on, p) {
|
||||
$('loading').hidden = !on;
|
||||
if (on) { $('loadbar').style.width = Math.round((p || 0) * 100) + '%'; $('loadtext').textContent = Math.round((p || 0) * 100) + '%'; }
|
||||
}
|
||||
function enterGame() {
|
||||
$('title').hidden = true; $('hud').hidden = false;
|
||||
GAME.running = true; GAME.paused = false;
|
||||
buildSky(); resizeRender(); snapCamera();
|
||||
GAME.lastAutosave = performance.now();
|
||||
GAME.drag = null; GAME.lmb = GAME.rmb = false; lastBagKey = '';
|
||||
hudDirty = true; renderHotbar();
|
||||
}
|
||||
function startNewWorld(seed, w, h) {
|
||||
auInit();
|
||||
showLoading(true, 0);
|
||||
setTimeout(() => {
|
||||
generateWorld(seed, w, h, null);
|
||||
GAME.playTime = 0; GAME.clip = null; GAME.paste = false; GAME.selDrag = null; GAME.tool = 0; GAME.dropMat = 0; GAME.matChosen = false; GAME.wallMat = RSTONE; GAME.filterCfg = { m: [], inv: 0 }; GAME.pieceIdx = 0;
|
||||
showLoading(false);
|
||||
enterGame();
|
||||
showCard({ kind: 'Welcome', title: 'The dig site', body: ['Fly with WASD. The Drill (1) breaks rock loose. The Vacuum (2) sucks up what you click on and blows it back out with right click.', 'You owe $20,000 on this claim. Sell what you dig and make at the trade dock next to you: anything that drops through its grate is paid for on the spot, and buyers post orders that pay far more. Every tip lives in the notebook (N).'], hold: 1.8 });
|
||||
saveWorld('auto', true);
|
||||
}, 30);
|
||||
}
|
||||
function startFromSave(sv) {
|
||||
auInit();
|
||||
try { deserializeWorld(sv.meta, sv.buffers); }
|
||||
catch (e) {
|
||||
toast(e && e.message ? e.message : 'That save could not be loaded.', { big: true, title: 'Save not loaded' });
|
||||
GAME.running = false; $('hud').hidden = true; $('title').hidden = false; if (!TITLE.raf) drawTitle();
|
||||
return false;
|
||||
}
|
||||
GAME.playTime = sv.playTime || 0;
|
||||
GAME.drag = null; GAME.matChosen = false; GAME.dropMat = 0;
|
||||
enterGame();
|
||||
return true;
|
||||
}
|
||||
async function quitToTitle() {
|
||||
await saveWorld('main', true);
|
||||
GAME.running = false; closeAllModals();
|
||||
$('hud').hidden = true; $('title').hidden = false;
|
||||
refreshContinue();
|
||||
if (!TITLE.raf) drawTitle();
|
||||
}
|
||||
async function refreshContinue() {
|
||||
const sv = await newestSave();
|
||||
const b = $('btn-continue');
|
||||
if (sv && sv.meta && sv.meta.v === SAVE_VERSION) {
|
||||
b.hidden = false;
|
||||
const d = new Date(sv.savedAt);
|
||||
$('continue-meta').textContent = `seed ${sv.meta.seed} · ${d.toLocaleDateString(undefined, { month: 'short', day: 'numeric' })} ${d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' })}`;
|
||||
} else b.hidden = true;
|
||||
}
|
||||
|
||||
// ---------- Modals ----------
|
||||
function anyModal() { return ['m-pause', 'm-settings', 'm-notebook', 'm-dialog'].some(id => !$(id).hidden); }
|
||||
function openModal(id) { $(id).hidden = false; GAME.paused = true; setTimeout(() => { const f = $(id).querySelector('button, select, input'); if (f && !GAME.usingPadMenu) { /* keep focus neutral for mouse users */ } }, 0); }
|
||||
function closeModal(id) { $(id).hidden = true; if (id === 'm-dialog') GAME.editRun = null; if (!anyModal()) GAME.paused = false; }
|
||||
function closeAllModals() { ['m-pause', 'm-settings', 'm-notebook', 'm-dialog'].forEach(id => $(id).hidden = true); GAME.paused = false; }
|
||||
function topModal() { for (const id of ['m-dialog', 'm-settings', 'm-notebook', 'm-pause']) if (!$(id).hidden) return id; return null; }
|
||||
function dialog(title, bodyHtml, buttons) {
|
||||
$('dlg-title').textContent = title; $('dlg-body').innerHTML = bodyHtml;
|
||||
const foot = $('dlg-foot'); foot.innerHTML = '';
|
||||
for (const b of buttons) {
|
||||
const btn = el('button', { class: 'btn ' + (b.cls || '') }, esc(b.label));
|
||||
btn.onclick = () => { playSfx('ui'); const keep = b.fn && b.fn(); if (!keep) closeModal('m-dialog'); };
|
||||
foot.appendChild(btn);
|
||||
}
|
||||
openModal('m-dialog');
|
||||
}
|
||||
document.querySelectorAll('[data-close]').forEach(b => b.addEventListener('click', () => { playSfx('ui'); closeModal(b.closest('.modal').id); }));
|
||||
|
||||
// pause menu
|
||||
$('pm-resume').onclick = () => { playSfx('ui'); closeModal('m-pause'); };
|
||||
$('pm-notebook').onclick = () => { playSfx('ui'); closeModal('m-pause'); openNotebook(); };
|
||||
$('pm-settings').onclick = () => { playSfx('ui'); openSettings(); };
|
||||
$('pm-save').onclick = () => { playSfx('ui'); saveWorld('main'); };
|
||||
$('pm-export').onclick = () => { playSfx('ui'); exportWorld(); };
|
||||
$('pm-import').onclick = () => { playSfx('ui'); $('importfile').click(); };
|
||||
$('importfile').onchange = e => { const f = e.target.files[0]; if (f) { closeAllModals(); importWorldFile(f); } e.target.value = ''; };
|
||||
$('pm-title').onclick = () => { playSfx('ui'); quitToTitle(); };
|
||||
function openPause() {
|
||||
$('pause-meta').textContent = `seed ${worldSeed} · ${W}×${H}`;
|
||||
openModal('m-pause');
|
||||
}
|
||||
Reference in New Issue
Block a user