Plane drifts forward at cruise speed, reverse trajectory right→left
Two adjustments to the intro plane: 1. Autonomous cruise speed. Adds BASE_SPEED (1/28 per second of wallclock) to targetProgress on every frame, so the plane crosses the screen on its own in ~28 s without any input. Mouse motion still adds a boost (one full traversal per ~4500 px of cursor travel), which feels like the plane "speeding up" when the user interacts. Time delta clamped to 0.1 s so the plane doesn't jump forward after the tab returns from background. 2. Reverse direction. Plane now enters from upper-right (x = +16), traverses to upper-left (x = -16), nose pointing -X. Wrapper rot.y flipped to +π/2; px formula flipped; banking angles inverted so the plane still rolls "into the turn" along its new direction. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
3829ab9af6
commit
48dbd14541
@ -56,8 +56,9 @@ loader.load(
|
|||||||
wrapper.add(model);
|
wrapper.add(model);
|
||||||
const targetSize = 8.5;
|
const targetSize = 8.5;
|
||||||
wrapper.scale.setScalar(targetSize / Math.max(size.x, size.y, size.z));
|
wrapper.scale.setScalar(targetSize / Math.max(size.x, size.y, size.z));
|
||||||
/* Pivote le modèle pour que le nez pointe vers la droite (+X) */
|
/* Pivote le modèle pour que le nez pointe vers la gauche (-X) :
|
||||||
wrapper.rotation.y = -Math.PI / 2;
|
l'avion entre par la droite et sort par la gauche. */
|
||||||
|
wrapper.rotation.y = Math.PI / 2;
|
||||||
planeHolder.add(wrapper);
|
planeHolder.add(wrapper);
|
||||||
},
|
},
|
||||||
undefined,
|
undefined,
|
||||||
@ -65,17 +66,16 @@ loader.load(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/* ── Souris ─────────────────────────────────────────────────────────────
|
/* ── Souris ─────────────────────────────────────────────────────────────
|
||||||
La souris fait AVANCER l'avion sur sa trajectoire : on accumule la
|
L'avion avance automatiquement à vitesse de croisière (BASE_SPEED).
|
||||||
distance parcourue par le curseur. Une fois que l'avion est sorti à
|
Bouger la souris ajoute un boost qui le pousse plus vite vers la fin.
|
||||||
droite (progress = 1), il reste sorti — la souris ne le ramène pas.
|
Une fois sorti à droite (progress = 1), il reste sorti.
|
||||||
|
|
||||||
On garde aussi mouseX (0..1) pour la parallaxe légère de la photo.
|
|
||||||
*/
|
*/
|
||||||
const FULL_DISTANCE = 3500; // pixels de souris pour traverser tout l'écran
|
const BASE_SPEED = 1 / 28; // 28 s pour traverser sans toucher la souris
|
||||||
|
const MOUSE_BOOST = 1 / 4500; // pixels de souris → progress (0..1)
|
||||||
const mouse = {
|
const mouse = {
|
||||||
targetProgress: 0, // accumulé, croissant
|
targetProgress: 0,
|
||||||
progress: 0, // suit avec lerp
|
progress: 0,
|
||||||
px: 0.5, py: 0.5 // dernier point connu (parallaxe fond)
|
px: 0.5, py: 0.5
|
||||||
};
|
};
|
||||||
|
|
||||||
let lastX = null, lastY = null;
|
let lastX = null, lastY = null;
|
||||||
@ -83,21 +83,21 @@ window.addEventListener('mousemove', (e) => {
|
|||||||
if (lastX !== null) {
|
if (lastX !== null) {
|
||||||
const dx = e.clientX - lastX;
|
const dx = e.clientX - lastX;
|
||||||
const dy = e.clientY - lastY;
|
const dy = e.clientY - lastY;
|
||||||
mouse.targetProgress = Math.min(1, mouse.targetProgress + Math.hypot(dx, dy) / FULL_DISTANCE);
|
mouse.targetProgress = Math.min(1, mouse.targetProgress + Math.hypot(dx, dy) * MOUSE_BOOST);
|
||||||
}
|
}
|
||||||
lastX = e.clientX; lastY = e.clientY;
|
lastX = e.clientX; lastY = e.clientY;
|
||||||
mouse.px = e.clientX / window.innerWidth;
|
mouse.px = e.clientX / window.innerWidth;
|
||||||
mouse.py = e.clientY / window.innerHeight;
|
mouse.py = e.clientY / window.innerHeight;
|
||||||
}, { passive: true });
|
}, { passive: true });
|
||||||
|
|
||||||
/* Mobile : la rotation du device fait progresser l'avion */
|
/* Mobile : la rotation du device pousse l'avion plus vite vers la fin */
|
||||||
let lastGamma = null, lastBeta = null;
|
let lastGamma = null, lastBeta = null;
|
||||||
window.addEventListener('deviceorientation', (e) => {
|
window.addEventListener('deviceorientation', (e) => {
|
||||||
if (e.gamma == null || e.beta == null) return;
|
if (e.gamma == null || e.beta == null) return;
|
||||||
if (lastGamma !== null) {
|
if (lastGamma !== null) {
|
||||||
const dg = e.gamma - lastGamma;
|
const dg = e.gamma - lastGamma;
|
||||||
const db = e.beta - lastBeta;
|
const db = e.beta - lastBeta;
|
||||||
mouse.targetProgress = Math.min(1, mouse.targetProgress + Math.hypot(dg, db) / 90);
|
mouse.targetProgress = Math.min(1, mouse.targetProgress + Math.hypot(dg, db) / 120);
|
||||||
}
|
}
|
||||||
lastGamma = e.gamma; lastBeta = e.beta;
|
lastGamma = e.gamma; lastBeta = e.beta;
|
||||||
mouse.px = Math.max(0, Math.min(1, (e.gamma + 30) / 60));
|
mouse.px = Math.max(0, Math.min(1, (e.gamma + 30) / 60));
|
||||||
@ -109,32 +109,37 @@ const root = document.documentElement;
|
|||||||
/* ── Render loop ───────────────────────────────────────────────────────── */
|
/* ── Render loop ───────────────────────────────────────────────────────── */
|
||||||
const clock = new THREE.Clock();
|
const clock = new THREE.Clock();
|
||||||
|
|
||||||
|
let lastT = 0;
|
||||||
function tick() {
|
function tick() {
|
||||||
const t = clock.getElapsedTime();
|
const t = clock.getElapsedTime();
|
||||||
|
const dt = Math.min(0.1, t - lastT); // clamp pour éviter les bonds après onglet en arrière-plan
|
||||||
|
lastT = t;
|
||||||
|
|
||||||
/* Lerp doux vers la cible (progrès cumulé) */
|
/* Avance autonome + cible cumulée par la souris, le tout limité à 1 */
|
||||||
|
mouse.targetProgress = Math.min(1, mouse.targetProgress + BASE_SPEED * dt);
|
||||||
|
/* Lerp doux pour fluidifier */
|
||||||
mouse.progress += (mouse.targetProgress - mouse.progress) * 0.06;
|
mouse.progress += (mouse.targetProgress - mouse.progress) * 0.06;
|
||||||
const p = mouse.progress;
|
const p = mouse.progress;
|
||||||
|
|
||||||
/* Variables CSS pour la parallaxe légère de la photo de fond */
|
/* Parallaxe légère de la photo de fond */
|
||||||
root.style.setProperty('--mx', ((mouse.px - 0.5) * 2).toFixed(4));
|
root.style.setProperty('--mx', ((mouse.px - 0.5) * 2).toFixed(4));
|
||||||
root.style.setProperty('--my', ((mouse.py - 0.5) * 2).toFixed(4));
|
root.style.setProperty('--my', ((mouse.py - 0.5) * 2).toFixed(4));
|
||||||
|
|
||||||
/* Trajectoire :
|
/* Trajectoire droite → gauche :
|
||||||
- p = 0 → arrive haut-gauche (hors champ)
|
- p = 0 → entre par la droite (hors champ)
|
||||||
- p = 0.5 → traverse au centre haut
|
- p = 0.5 → traverse au centre haut
|
||||||
- p = 1 → sortie à droite (hors champ)
|
- p = 1 → sort par la gauche (hors champ)
|
||||||
*/
|
*/
|
||||||
const px = -16 + p * 32;
|
const px = 16 - p * 32;
|
||||||
const py = 7 - p * 5;
|
const py = 7 - p * 5;
|
||||||
const bob = Math.sin(t * 0.9) * 0.12;
|
const bob = Math.sin(t * 0.9) * 0.12;
|
||||||
|
|
||||||
planeHolder.position.set(px, py + bob, 0);
|
planeHolder.position.set(px, py + bob, 0);
|
||||||
|
|
||||||
/* Banking subtil — penche en pivotant */
|
/* Banking subtil — direction inversée par rapport à un vol gauche→droite */
|
||||||
const targetRoll = -0.18 - (p - 0.5) * 0.25;
|
const targetRoll = 0.18 + (p - 0.5) * 0.25;
|
||||||
const targetPitch = -0.18 - p * 0.10;
|
const targetPitch = -0.18 - p * 0.10;
|
||||||
const targetYaw = (p - 0.5) * 0.10;
|
const targetYaw = -(p - 0.5) * 0.10;
|
||||||
planeHolder.rotation.z += (targetRoll - planeHolder.rotation.z) * 0.08;
|
planeHolder.rotation.z += (targetRoll - planeHolder.rotation.z) * 0.08;
|
||||||
planeHolder.rotation.x += (targetPitch - planeHolder.rotation.x) * 0.08;
|
planeHolder.rotation.x += (targetPitch - planeHolder.rotation.x) * 0.08;
|
||||||
planeHolder.rotation.y += (targetYaw - planeHolder.rotation.y) * 0.08;
|
planeHolder.rotation.y += (targetYaw - planeHolder.rotation.y) * 0.08;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user