import { canvas, resize, cursor, brushSize, setBrushSize } from './state.js'; import { setupUI, handleInput, setLastPos, updateBrushUI } from './ui.js'; import { update } from './physics.js'; import { draw } from './renderer.js'; import { loadSettings, config, saveSettings } from './config.js'; let updateAccumulator = 0; export function stepOnce() { update(); draw(); } function init() { loadSettings(); if (config.brush?.size) { setBrushSize(config.brush.size); } resize(); window.addEventListener('resize', resize); setupUI(); // Input Handling let isMouseDown = false; let isRightClick = false; canvas.addEventListener('contextmenu', (e) => e.preventDefault()); canvas.addEventListener('mousedown', (e) => { isMouseDown = true; isRightClick = (e.button === 2); cursor.visible = true; cursor.x = e.clientX; cursor.y = e.clientY; handleInput(e, isRightClick ? 'eraser' : null); }); window.addEventListener('mouseup', () => { isMouseDown = false; isRightClick = false; setLastPos(null); }); canvas.addEventListener('mousemove', (e) => { cursor.visible = true; cursor.x = e.clientX; cursor.y = e.clientY; if (isMouseDown) { handleInput(e, isRightClick ? 'eraser' : null); } }); canvas.addEventListener('mouseenter', () => { cursor.visible = true; }); canvas.addEventListener('mouseleave', () => { cursor.visible = false; setLastPos(null); }); // Mouse wheel to change brush size canvas.addEventListener('wheel', (e) => { e.preventDefault(); const delta = e.deltaY < 0 ? 1 : -1; setBrushSize(brushSize + delta); config.brush.size = brushSize; saveSettings(); updateBrushUI(); }, { passive: false }); // Touch Support canvas.addEventListener('touchstart', (e) => { isMouseDown = true; if (e.touches.length > 0) { cursor.visible = true; cursor.x = e.touches[0].clientX; cursor.y = e.touches[0].clientY; } handleInput(e); e.preventDefault(); }, { passive: false }); canvas.addEventListener('touchend', (e) => { if (e.touches.length === 0) { isMouseDown = false; cursor.visible = false; setLastPos(null); } }); canvas.addEventListener('touchmove', (e) => { if (e.touches.length > 0) { cursor.visible = true; cursor.x = e.touches[0].clientX; cursor.y = e.touches[0].clientY; } if (isMouseDown) handleInput(e); e.preventDefault(); }, { passive: false }); // Keyboard Shortcuts window.addEventListener('keydown', (e) => { if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; if (e.code === 'Space') { e.preventDefault(); config.time.paused = !config.time.paused; saveSettings(); const pauseBtn = document.getElementById('togglePause'); if (pauseBtn) pauseBtn.textContent = config.time.paused ? '▶' : '⏸'; } else if (e.code === 'KeyS' || e.code === 'Period') { if (config.time.paused) { stepOnce(); } } else if (e.code === 'BracketLeft') { setBrushSize(brushSize - 1); config.brush.size = brushSize; saveSettings(); updateBrushUI(); } else if (e.code === 'BracketRight') { setBrushSize(brushSize + 1); config.brush.size = brushSize; saveSettings(); updateBrushUI(); } }); gameLoop(); } function gameLoop() { if (!config.time.paused) { updateAccumulator += config.time.speed; while (updateAccumulator >= 1) { update(); updateAccumulator -= 1; if (updateAccumulator > 30) { updateAccumulator = 0; break; } } } draw(); requestAnimationFrame(gameLoop); } init();