CTA emerges from the plane when it reaches center
Hide the gold pill button at page load (opacity 0, scale 0.05, translated 27 vh up — roughly where the plane is when it crosses the viewport center). When the plane's progress reaches 0.5, the tick loop adds a `.revealed` class to .cta-btn; CSS variables flip and a 1.2 s spring transition lands the button at viewport center at full size. Pulse halo (::after) is dormant until the .revealed class lands, so it doesn't waste cycles on a hidden element. Hover scale (1.04) re-introduced on `.cta-btn.revealed:hover` with the original 0.32 s transition so it doesn't fight the slow emerge tween. Plane and parcel logic untouched. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4b622a7d85
commit
22c57e5b41
@ -117,12 +117,23 @@ html, body {
|
|||||||
|
|
||||||
.layer-three { display: block; z-index: 2; }
|
.layer-three { display: block; z-index: 2; }
|
||||||
|
|
||||||
/* ── BOUTON CTA centré ──────────────────────────────────────────────────── */
|
/* ── BOUTON CTA centré ────────────────────────────────────────────────────
|
||||||
|
État caché : positionné là où l'avion est au centre de sa course
|
||||||
|
(~27% au-dessus du centre du viewport), à scale ≈ 0. Quand le JS
|
||||||
|
ajoute la classe `.revealed` (au moment où l'avion atteint p ≥ 0.5),
|
||||||
|
les variables CSS basculent et le bouton « sort » de l'avion en
|
||||||
|
grossissant jusqu'à sa taille finale au centre. */
|
||||||
.cta-btn {
|
.cta-btn {
|
||||||
|
--cta-y: -27vh; /* offset vertical : 0 = centré */
|
||||||
|
--cta-scale: 0.05;
|
||||||
|
--cta-opacity: 0;
|
||||||
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, calc(-50% + var(--cta-y))) scale(var(--cta-scale));
|
||||||
|
opacity: var(--cta-opacity);
|
||||||
|
pointer-events: none;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -142,12 +153,25 @@ html, body {
|
|||||||
0 20px 60px rgba(197, 165, 90, 0.55),
|
0 20px 60px rgba(197, 165, 90, 0.55),
|
||||||
0 0 0 0 rgba(197, 165, 90, 0.4),
|
0 0 0 0 rgba(197, 165, 90, 0.4),
|
||||||
inset 0 1px 0 rgba(255, 255, 255, 0.45);
|
inset 0 1px 0 rgba(255, 255, 255, 0.45);
|
||||||
transition: box-shadow 0.32s cubic-bezier(0.2, 0.8, 0.2, 1),
|
transition:
|
||||||
transform 0.32s cubic-bezier(0.2, 0.8, 0.2, 1);
|
transform 1.2s cubic-bezier(0.34, 1.5, 0.64, 1),
|
||||||
|
opacity 0.5s ease 0.05s,
|
||||||
|
box-shadow 0.32s cubic-bezier(0.2, 0.8, 0.2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.cta-btn:hover {
|
.cta-btn.revealed {
|
||||||
transform: translate(-50%, -50%) scale(1.04);
|
--cta-y: 0vh;
|
||||||
|
--cta-scale: 1;
|
||||||
|
--cta-opacity: 1;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hover seulement après la révélation, avec une transition rapide */
|
||||||
|
.cta-btn.revealed:hover {
|
||||||
|
--cta-scale: 1.04;
|
||||||
|
transition:
|
||||||
|
transform 0.32s cubic-bezier(0.2, 0.8, 0.2, 1),
|
||||||
|
box-shadow 0.32s cubic-bezier(0.2, 0.8, 0.2, 1);
|
||||||
box-shadow:
|
box-shadow:
|
||||||
0 28px 75px rgba(197, 165, 90, 0.7),
|
0 28px 75px rgba(197, 165, 90, 0.7),
|
||||||
0 0 0 12px rgba(197, 165, 90, 0.12),
|
0 0 0 12px rgba(197, 165, 90, 0.12),
|
||||||
@ -177,9 +201,12 @@ html, body {
|
|||||||
inset: -3px;
|
inset: -3px;
|
||||||
border-radius: 50px;
|
border-radius: 50px;
|
||||||
border: 2px solid rgba(197, 165, 90, 0.55);
|
border: 2px solid rgba(197, 165, 90, 0.55);
|
||||||
animation: ctaPulse 2.8s ease-out infinite;
|
animation: none; /* halo dormant tant que le bouton n'est pas révélé */
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
.cta-btn.revealed::after {
|
||||||
|
animation: ctaPulse 2.8s ease-out 1s infinite; /* démarre après l'arrivée du bouton */
|
||||||
|
}
|
||||||
@keyframes ctaPulse {
|
@keyframes ctaPulse {
|
||||||
0% { transform: scale(1); opacity: 0.7; }
|
0% { transform: scale(1); opacity: 0.7; }
|
||||||
100% { transform: scale(1.18); opacity: 0; }
|
100% { transform: scale(1.18); opacity: 0; }
|
||||||
|
|||||||
@ -239,6 +239,13 @@ window.addEventListener('deviceorientation', (e) => {
|
|||||||
|
|
||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
|
|
||||||
|
/* ── Révélation du CTA ─────────────────────────────────────────────────
|
||||||
|
Quand l'avion arrive au centre de l'écran (p ≥ 0.5), on bascule la
|
||||||
|
classe `.revealed` sur le bouton. La CSS gère l'animation (translate
|
||||||
|
du haut vers le centre + scale 0.05 → 1, ~1.2 s). */
|
||||||
|
const ctaBtn = document.querySelector('.cta-btn');
|
||||||
|
let ctaRevealed = false;
|
||||||
|
|
||||||
/* ── Render loop ───────────────────────────────────────────────────────── */
|
/* ── Render loop ───────────────────────────────────────────────────────── */
|
||||||
const clock = new THREE.Clock();
|
const clock = new THREE.Clock();
|
||||||
|
|
||||||
@ -278,6 +285,13 @@ function tick() {
|
|||||||
}
|
}
|
||||||
updateParcels(dt, t);
|
updateParcels(dt, t);
|
||||||
|
|
||||||
|
/* Au moment où l'avion atteint le centre, on déclenche la sortie du
|
||||||
|
CTA (l'animation CSS s'en occupe ensuite). One-shot. */
|
||||||
|
if (!ctaRevealed && p >= 0.5) {
|
||||||
|
ctaRevealed = true;
|
||||||
|
ctaBtn?.classList.add('revealed');
|
||||||
|
}
|
||||||
|
|
||||||
/* Avec nez à -X et up = +Y :
|
/* Avec nez à -X et up = +Y :
|
||||||
- rotation.z = PITCH (négatif = nez en l'air)
|
- rotation.z = PITCH (négatif = nez en l'air)
|
||||||
- rotation.x = ROLL
|
- rotation.x = ROLL
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user