From fd0acea058bbd629f42bd7cd222f65bde4819e62 Mon Sep 17 00:00:00 2001 From: MVA Global Fret Date: Tue, 5 May 2026 14:41:34 +0200 Subject: [PATCH] Mobile: lighter render path + touch-to-accelerate the plane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Detects mobile via UA + 768 px media query (IS_MOBILE constant) and flips three knobs: - Renderer: antialias off, pixelRatio capped at 1.5 (vs 2 on desktop) - Parcels: spawn every 2.4 s (vs 1.4 s on desktop) to keep clone+ draw cost down Adds touch handlers so users without a mouse can speed the plane up: - touchstart bumps `touchBoost` from 1 to 6 → BASE_SPEED is multiplied by 6 each tick while a finger is on the screen - touchmove also feeds Math.hypot(dx, dy) * MOUSE_BOOST into targetProgress, so swiping advances the plane the same way mouse motion does on desktop - touchend / touchcancel reset touchBoost to 1 and clear last-touch coordinates Co-Authored-By: Claude Opus 4.6 --- js/intro-scene.js | 51 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/js/intro-scene.js b/js/intro-scene.js index 067d9a1..cd8a7c3 100644 --- a/js/intro-scene.js +++ b/js/intro-scene.js @@ -12,12 +12,20 @@ import * as THREE from 'three'; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; +/* ── Détection mobile ────────────────────────────────────────────────── + Sur mobile : on coupe l'antialiasing, on plafonne le pixel ratio à + 1.5 et on espace davantage les spawns de colis pour garder ~60 fps. */ +const IS_MOBILE = /iPhone|iPad|iPod|Android|Mobile/i.test(navigator.userAgent) + || window.matchMedia('(max-width: 768px)').matches; + /* ── Renderer & camera ─────────────────────────────────────────────────── */ const canvas = document.getElementById('three-canvas'); const renderer = new THREE.WebGLRenderer({ - canvas, alpha: true, antialias: true, powerPreference: 'high-performance' + canvas, alpha: true, + antialias: !IS_MOBILE, + powerPreference: 'high-performance' }); -renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); +renderer.setPixelRatio(Math.min(window.devicePixelRatio, IS_MOBILE ? 1.5 : 2)); renderer.outputColorSpace = THREE.SRGBColorSpace; renderer.toneMapping = THREE.ACESFilmicToneMapping; renderer.toneMappingExposure = 1.05; @@ -72,7 +80,7 @@ loader.load( parachute (mêmes parent → même position/rotation/échelle), et placée pile au niveau du harnais pour que l'attachement soit lisible. */ -const PARCEL_SPAWN_EVERY = 1.4; +const PARCEL_SPAWN_EVERY = IS_MOBILE ? 2.4 : 1.4; // moins fréquent sur mobile const PARCEL_FALL_SPEED = 1.4; const PARCEL_DRIFT = 0.45; const PARCEL_INITIAL_SCALE = 0.45; @@ -237,6 +245,38 @@ window.addEventListener('deviceorientation', (e) => { mouse.py = Math.max(0, Math.min(1, (e.beta - 20) / 60)); }, { passive: true }); +/* Tactile : tant que le doigt est posé, l'avion accélère (multiplicateur + sur BASE_SPEED). Le swipe ajoute aussi du progrès cumulé comme la + souris sur desktop. */ +let touchBoost = 1; +let lastTouchX = null, lastTouchY = null; + +window.addEventListener('touchstart', (e) => { + touchBoost = 6; + if (e.touches[0]) { + lastTouchX = e.touches[0].clientX; + lastTouchY = e.touches[0].clientY; + } +}, { passive: true }); + +window.addEventListener('touchmove', (e) => { + const t0 = e.touches[0]; + if (!t0) return; + if (lastTouchX !== null) { + const dx = t0.clientX - lastTouchX; + const dy = t0.clientY - lastTouchY; + mouse.targetProgress = Math.min(1, mouse.targetProgress + Math.hypot(dx, dy) * MOUSE_BOOST); + } + lastTouchX = t0.clientX; + lastTouchY = t0.clientY; + mouse.px = t0.clientX / window.innerWidth; + mouse.py = t0.clientY / window.innerHeight; +}, { passive: true }); + +function endTouch() { touchBoost = 1; lastTouchX = lastTouchY = null; } +window.addEventListener('touchend', endTouch, { passive: true }); +window.addEventListener('touchcancel', endTouch, { passive: true }); + const root = document.documentElement; /* ── Révélation du CTA ───────────────────────────────────────────────── @@ -255,8 +295,9 @@ function tick() { const dt = Math.min(0.1, t - lastT); // clamp pour éviter les bonds après onglet en arrière-plan lastT = t; - /* Avance autonome + cible cumulée par la souris, le tout limité à 1 */ - mouse.targetProgress = Math.min(1, mouse.targetProgress + BASE_SPEED * dt); + /* Avance autonome + boost tactile (×6 tant qu'un doigt touche l'écran) + + cible cumulée par souris/swipe, le tout limité à 1 */ + mouse.targetProgress = Math.min(1, mouse.targetProgress + BASE_SPEED * touchBoost * dt); /* Lerp doux pour fluidifier */ mouse.progress += (mouse.targetProgress - mouse.progress) * 0.06; const p = mouse.progress;