Skip to content

Commit a2f9230

Browse files
authored
Merge pull request #5 from alphaonelabs/copilot/fix-localstorage-robot-work
Persist robot state across page refreshes via localStorage
2 parents 84d7e7e + 1b56d97 commit a2f9230

1 file changed

Lines changed: 89 additions & 0 deletions

File tree

home.html

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,8 @@
243243

244244
// ========== BLOCKS ==========
245245
let blocks = [];
246+
const STORAGE_KEY = 'robotics_playground_state';
247+
let lastSaveTime = 0;
246248

247249
function generateBlocks() {
248250
blocks = [];
@@ -301,6 +303,7 @@
301303
}
302304
robot.holdingBlock = null;
303305
showMsg('Dropped!');
306+
saveState();
304307
} else {
305308
// PICK
306309
for (let b of blocks) {
@@ -312,6 +315,7 @@
312315
b.held = true;
313316
robot.holdingBlock = b.id;
314317
showMsg('Grabbed! SPACE to drop');
318+
saveState();
315319
break;
316320
}
317321
}
@@ -355,6 +359,7 @@
355359
}
356360
updatePartsList();
357361
showMsg(`${type.charAt(0).toUpperCase() + type.slice(1)} added!`);
362+
saveState();
358363
}
359364

360365
function removePart(type) {
@@ -396,6 +401,7 @@
396401

397402
updatePartsList();
398403
showMsg(`${type.charAt(0).toUpperCase() + type.slice(1)} removed!`);
404+
saveState();
399405
}
400406

401407
function resetAll() {
@@ -422,6 +428,7 @@
422428
document.getElementById('detection-info').innerHTML = '<div class="text-gray-500">LiDAR not installed</div>';
423429
document.getElementById('detection-indicator').classList.add('hidden');
424430
updatePartsList();
431+
localStorage.removeItem(STORAGE_KEY);
425432
}
426433

427434
function updatePartsList() {
@@ -432,15 +439,18 @@
432439
function updatePower() {
433440
motorPower = +document.getElementById('power-slider').value;
434441
document.getElementById('power-val').textContent = motorPower + '%';
442+
saveState();
435443
}
436444

437445
function updateTurn() {
438446
turnSpeed = +document.getElementById('turn-slider').value;
439447
document.getElementById('turn-val').textContent = turnSpeed + '°';
448+
saveState();
440449
}
441450

442451
function updateColor() {
443452
robot.color = document.getElementById('color-picker').value;
453+
saveState();
444454
}
445455

446456
// ========== GAME LOOP ==========
@@ -731,12 +741,18 @@
731741
function loop() {
732742
update();
733743
render();
744+
const now = Date.now();
745+
if (robot.parts.chassis && now - lastSaveTime > 1000) {
746+
saveState();
747+
lastSaveTime = now;
748+
}
734749
requestAnimationFrame(loop);
735750
}
736751

737752
// ========== LIDAR DETECTION ==========
738753
let lastDetectedId = null;
739754

755+
loadState();
740756
loop();
741757

742758
function segmentsIntersect(x1, y1, x2, y2, x3, y3, x4, y4) {
@@ -832,6 +848,79 @@
832848
indicator.classList.add('hidden');
833849
}
834850
}
851+
852+
// ========== STATE PERSISTENCE ==========
853+
function saveState() {
854+
try {
855+
const state = {
856+
robot: {
857+
x: robot.x,
858+
y: robot.y,
859+
angle: robot.angle,
860+
color: robot.color,
861+
holdingBlock: robot.holdingBlock,
862+
parts: { ...robot.parts },
863+
},
864+
motorPower,
865+
turnSpeed,
866+
blocks: blocks.map(b => ({ ...b })),
867+
};
868+
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
869+
} catch (e) {
870+
// localStorage may be unavailable
871+
}
872+
}
873+
874+
function loadState() {
875+
try {
876+
const saved = localStorage.getItem(STORAGE_KEY);
877+
if (!saved) return;
878+
const state = JSON.parse(saved);
879+
if (!state) return;
880+
881+
if (state.robot) {
882+
robot.x = typeof state.robot.x === 'number' ? Math.max(35, Math.min(canvas.width - 35, state.robot.x)) : canvas.width / 2;
883+
robot.y = typeof state.robot.y === 'number' ? Math.max(35, Math.min(canvas.height - 35, state.robot.y)) : canvas.height / 2;
884+
robot.angle = typeof state.robot.angle === 'number' ? state.robot.angle : 0;
885+
robot.color = state.robot.color || '#0d9488';
886+
robot.holdingBlock = state.robot.holdingBlock !== undefined ? state.robot.holdingBlock : null;
887+
if (state.robot.parts) {
888+
robot.parts = { ...robot.parts, ...state.robot.parts };
889+
}
890+
}
891+
892+
if (typeof state.motorPower === 'number') {
893+
motorPower = state.motorPower;
894+
document.getElementById('power-slider').value = motorPower;
895+
document.getElementById('power-val').textContent = motorPower + '%';
896+
}
897+
if (typeof state.turnSpeed === 'number') {
898+
turnSpeed = state.turnSpeed;
899+
document.getElementById('turn-slider').value = turnSpeed;
900+
document.getElementById('turn-val').textContent = turnSpeed + '°';
901+
}
902+
903+
if (Array.isArray(state.blocks) && state.blocks.length > 0) {
904+
blocks = state.blocks;
905+
document.getElementById('block-count').textContent = blocks.length;
906+
}
907+
908+
document.getElementById('color-picker').value = robot.color;
909+
910+
if (robot.parts.chassis) {
911+
document.getElementById('start-prompt').classList.add('hidden');
912+
}
913+
if (robot.parts.camera) {
914+
document.getElementById('camera-feed').classList.remove('hidden');
915+
}
916+
if (robot.parts.lidar) {
917+
updateDetectionUI(null);
918+
}
919+
updatePartsList();
920+
} catch (e) {
921+
// Corrupted state, ignore
922+
}
923+
}
835924
</script>
836925
</body>
837926
</html>

0 commit comments

Comments
 (0)