diff --git a/index.php b/index.php index 52da689..8fb4a68 100644 --- a/index.php +++ b/index.php @@ -205,14 +205,6 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? '';

Active Session Controller

-

Time Remaining: 00:00

- - @@ -231,13 +223,11 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; const speedValue = document.getElementById('speedValue'); const startButton = document.getElementById('startButton'); const stopButton = document.getElementById('stopButton'); - const timerDisplay = document.getElementById('timerDisplay'); - const durationSelect = document.getElementById('durationSelect'); + let gamepad = null; let vibrationInterval = null; - let sessionTimer = null; - let timeRemaining = 0; + let currentPattern = ''; // Gamepad API @@ -252,11 +242,33 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; window.addEventListener('gamepaddisconnected', (e) => { console.log('Gamepad disconnected from index %d: %s', e.gamepad.index, e.gamepad.id); - gamepad = null; + if (gamepad && gamepad.index === e.gamepad.index) { + gamepad = null; + } updateGamepadStatus(); stopMassage(); }); + // Polling for gamepads (required for some browsers/situations) + setInterval(() => { + const gamepads = navigator.getGamepads(); + let found = false; + for (let i = 0; i < gamepads.length; i++) { + if (gamepads[i]) { + if (!gamepad) { + gamepad = gamepads[i]; + updateGamepadStatus(); + } + found = true; + break; + } + } + if (!found && gamepad) { + gamepad = null; + updateGamepadStatus(); + } + }, 1000); + function updateGamepadStatus() { if (gamepad) { gamepadStatus.textContent = 'Connected'; @@ -264,51 +276,73 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; gamepadIdDisplay.textContent = `ID: ${gamepad.id}`; startButton.disabled = false; } else { - gamepadStatus.textContent = 'Disconnected'; + gamepadStatus.textContent = 'Disconnected (Press a button!)'; gamepadStatus.className = 'status-disconnected'; - gamepadIdDisplay.textContent = ''; + gamepadIdDisplay.textContent = 'Ensure your controller is plugged in and press any button to activate.'; startButton.disabled = true; } } // Haptic Patterns const patterns = { - knead: (intensity, speed) => [{ startDelay: 0, duration: 100 * speed, weakMagnitude: intensity * 0.7, strongMagnitude: intensity }, - { startDelay: 100 * speed, duration: 100 * speed, weakMagnitude: intensity, strongMagnitude: intensity * 0.7 }], - tap: (intensity, speed) => [{ startDelay: 0, duration: 50 * speed, weakMagnitude: intensity, strongMagnitude: intensity }], - wave: (intensity, speed) => [{ startDelay: 0, duration: 200 * speed, weakMagnitude: intensity * 0.2, strongMagnitude: intensity }, - { startDelay: 200 * speed, duration: 200 * speed, weakMagnitude: intensity, strongMagnitude: intensity * 0.2 }], - sports_recovery: (intensity, speed) => [ // Strong, pulsating vibration - { startDelay: 0, duration: 150 * speed, weakMagnitude: intensity, strongMagnitude: intensity }, - { startDelay: 150 * speed, duration: 50 * speed, weakMagnitude: intensity * 0.2, strongMagnitude: intensity * 0.2 }, - { startDelay: 200 * speed, duration: 150 * speed, weakMagnitude: intensity, strongMagnitude: intensity }, - { startDelay: 350 * speed, duration: 50 * speed, weakMagnitude: intensity * 0.2, strongMagnitude: intensity * 0.2 }, + knead: (intensity, speed) => [ + { duration: 200 * speed, weakMagnitude: intensity * 0.5, strongMagnitude: intensity }, + { duration: 200 * speed, weakMagnitude: intensity, strongMagnitude: intensity * 0.5 } + ], + tap: (intensity, speed) => [ + { duration: 100 * speed, weakMagnitude: intensity, strongMagnitude: intensity }, + { duration: 100 * speed, weakMagnitude: 0, strongMagnitude: 0 } + ], + wave: (intensity, speed) => [ + { duration: 400 * speed, weakMagnitude: intensity * 0.2, strongMagnitude: intensity }, + { duration: 400 * speed, weakMagnitude: intensity, strongMagnitude: intensity * 0.2 } + ], + sports_recovery: (intensity, speed) => [ + { duration: 150 * speed, weakMagnitude: intensity, strongMagnitude: intensity }, + { duration: 50 * speed, weakMagnitude: 0, strongMagnitude: 0 }, + { duration: 150 * speed, weakMagnitude: intensity, strongMagnitude: intensity }, + { duration: 150 * speed, weakMagnitude: 0.2, strongMagnitude: 0.2 } ] }; + let patternStep = 0; + function playHapticPattern() { - if (gamepad && gamepad.vibrationActuator) { + // Re-fetch gamepad to get the most up-to-date object + const gamepads = navigator.getGamepads(); + const gp = gamepads[gamepad?.index]; + + if (gp && gp.vibrationActuator) { const selectedPattern = patternSelect.value; const intensity = parseFloat(intensityRange.value); const speed = parseFloat(speedRange.value); - currentPattern = selectedPattern; // Store the current pattern + const steps = patterns[selectedPattern](intensity, speed); + const step = steps[patternStep % steps.length]; - const effect = patterns[selectedPattern](intensity, speed); - gamepad.vibrationActuator.playEffect('dual-rumble', { + gp.vibrationActuator.playEffect('dual-rumble', { startDelay: 0, - duration: 0, // Duration will be managed by interval - weakMagnitude: 0, - strongMagnitude: 0, - haptics: effect + duration: step.duration, + weakMagnitude: step.weakMagnitude, + strongMagnitude: step.strongMagnitude }); + + patternStep++; + + // Schedule next step + vibrationInterval = setTimeout(playHapticPattern, step.duration); } } function startMassage() { if (!gamepad) { - alert('Please connect a gamepad first!'); - return; + // Try to get gamepad from navigator if not detected by event + const gamepads = navigator.getGamepads(); + gamepad = Array.from(gamepads).find(g => g !== null); + if (!gamepad) { + alert('Please connect a gamepad first and press any button!'); + return; + } } startButton.disabled = true; @@ -316,39 +350,25 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; patternSelect.disabled = true; intensityRange.disabled = true; speedRange.disabled = true; - durationSelect.disabled = true; - timeRemaining = parseInt(durationSelect.value); - updateTimerDisplay(); + patternStep = 0; - // Start the haptic pattern + // Start the haptic pattern loop playHapticPattern(); - // Restart pattern every cycle if it has a specific duration (e.g., tap) - vibrationInterval = setInterval(playHapticPattern, 400 * parseFloat(speedRange.value)); // Adjust interval based on pattern complexity - // Start the session timer - sessionTimer = setInterval(() => { - timeRemaining--; - updateTimerDisplay(); - if (timeRemaining <= 0) { - stopMassage(); - } - }, 1000); - - logSession(currentPattern, parseFloat(intensityRange.value), parseInt(durationSelect.value)); + logSession(patternSelect.value, parseFloat(intensityRange.value), 0); // Log with 0 duration for manual sessions } function stopMassage() { if (vibrationInterval) { - clearInterval(vibrationInterval); + clearTimeout(vibrationInterval); vibrationInterval = null; } - if (sessionTimer) { - clearInterval(sessionTimer); - sessionTimer = null; - } - if (gamepad && gamepad.vibrationActuator) { - gamepad.vibrationActuator.reset(); + // Stop vibration + const gamepads = navigator.getGamepads(); + const gp = gamepads[gamepad?.index]; + if (gp && gp.vibrationActuator) { + gp.vibrationActuator.reset(); } startButton.disabled = false; @@ -356,16 +376,9 @@ $projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; patternSelect.disabled = false; intensityRange.disabled = false; speedRange.disabled = false; - durationSelect.disabled = false; - - timerDisplay.textContent = '00:00'; } - function updateTimerDisplay() { - const minutes = Math.floor(timeRemaining / 60); - const seconds = timeRemaining % 60; - timerDisplay.textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; - } + // Event Listeners startButton.addEventListener('click', startMassage);