HoverGratuit

Gravity Simulation

Cliquez dans le cadre pour lancer des balles colorées soumises à la gravité — elles rebondissent sur les bords, perdent leur élan peu à peu et s'accumulent au sol. Chaque clic en ajoute une nouvelle, indéfiniment.

JSPhysicsInteractive

Mis à jour le

Cliquez pour ajouter des balles
Survolez ou cliquez la scène pour interagir

Cet effet est gratuit — la catégorie Hover en contient 48 au total, dont 5 gratuits. Effect.Labs regroupe 840 effets vanilla. Découvrir la catégorie →

Exemples d'usage

Grallux — Gravité Tapez pour faire tomber une balle
Cliquez pour ajouter une balle

① Terrain de jeu de physique — visualisation de la gravité pour des élèves de CM1

QuandDans l'application scolaire Grallux, les élèves tapent l'écran ou cliquent dans la zone pour faire tomber des balles colorées et observer leurs trajectoires et rebonds.
PourquoiManipuler des objets virtuels soumis à la gravité rend le concept tangible et ludique ; chaque balle ajoutée montre qu'elles tombent toutes au même rythme, illustrant l'égalité gravitationnelle.
RéglagesFond bleu nuit pour rappeler un tableau de physique ; balles de taille standard (30 px) ; couleurs aléatoires pour distinguer les lancers de chaque élève.
Événements en direct ● En direct
314
Inscriptions du jour
73
Achats
$3 180
Revenus
Nouveaux événements ici

② Dashboard de métriques — visualisation des nouveaux événements en temps réel

QuandChaque nouvelle conversion ou inscription déclenche automatiquement l'apparition d'une balle dans la zone du bas du tableau de bord ; le rythme des chutes donne une impression immédiate de l'activité sans lire de chiffre.
PourquoiUn indicateur animé périphérique attire l'œil sans interrompre le travail ; le comportement physique (accumulation, rebond) est plus expressif qu'un simple compteur incrémental.
RéglagesBalles de couleur uniforme (verte) sur fond sombre de tableau de bord ; le script data-scenes simule des arrivées toutes les 1,6 s via dispatchEvent sur le container.
Drevorn ✓ Réservation confirmée
À bientôt le 24 décembre !
Confirmation envoyée dans votre boîte

③ Célébration de confirmation de réservation — application d'hébergement en ligne

QuandAprès validation de la réservation, un bouton « Ajouter au calendrier » lance des balles colorées en fond de page — chaque clic sur le bouton CTA ajoute une balle au bon endroit dans le container de gravité.
PourquoiUne réaction visuelle exubérante au moment de la confirmation crée un souvenir positif et renforce le sentiment d'accomplissement de la réservation.
RéglagesBalles colorées en superposition sur le message de confirmation (z-index élevé sur le texte) ; les balles rebondissent en fond sans cacher les informations essentielles.

Comment ça marche

Le cadre .fx-0381-root (250 px de haut) contient le conteneur .gs381-container. À chaque clic (ou touchstart), le script crée un div.gs381-ball positionné là où le curseur ou le doigt a touché le cadre, avec une vélocité initiale aléatoire faible (vx entre −2 et +2 px, vy entre −4 et −1 px vers le haut). La couleur de chaque balle est choisie aléatoirement dans une palette de cinq teintes (violet, rose, indigo, cyan, vert).

La boucle requestAnimationFrame met à jour chaque balle à chaque image avec un pas normalisé à 60 images/s : f = dt / 16.67. La gravité ajoute 0,5 × f à vy ; la friction multiplie les deux composantes par 0,99 × f. Au rebond sur le sol, vy est multiplié par −0,7 et vx par 0,8. Rebond sur les côtés : vx inversé. Un IntersectionObserver met la boucle en pause quand le cadre est hors de l'écran.

Accessibilité

  • Toucher : l'événement touchstart ajoute une balle à l'endroit du doigt, avec preventDefault() pour éviter le défilement. L'effet fonctionne complètement sur mobile.
  • Clavier : l'effet ne réagit pas aux touches. Si un usage accessible est requis, ajoutez un <button> « Ajouter une balle » qui simule un clic au centre du conteneur.
  • Mouvement réduit : sous prefers-reduced-motion: reduce, la boucle ne démarre pas. Les clics créent bien une balle visible au point de clic, mais aucune gravité ni rebond ne se produisent — l'état résultant est lisible et statique.
  • Rôle décoratif : les balles sont purement visuelles. Le label « Cliquez pour ajouter des balles » est lisible, et son équivalent anglais est fourni dans html_en.

Compatibilité navigateur

DOM pur et CSS, aucune dépendance. IntersectionObserver disponible depuis Chrome 51, Firefox 55, Safari 12.1. Physique par requestAnimationFrame normalisée sur le temps écoulé. Non vérifié sur Safari réel ; attendu complet.

Chrome 51+✓ Complet (mesuré)
Firefox 55+✓ Complet (mesuré)
Safari 12.1+✓ Attendu complet (non mesuré)
Edge 79+✓ Complet (mesuré)
Mobile iOS 12.2+✓ Complet au toucher (non mesuré)
Android Chrome 51+✓ Complet au toucher (non mesuré)

Sans JavaScript, le cadre s'affiche vide avec le seul label centré. Sans IntersectionObserver, la boucle tourne aussi hors écran.

Le code

Copiez les trois blocs dans votre page. Aucune dépendance.

HTML
<div class="fx-0381-root">
  <div class="gs381-container">
    <span class="gs381-label">Cliquez pour ajouter des balles</span>
  </div>
</div>
CSS
.fx-0381-root,.fx-0381-root *,.fx-0381-root *::before,.fx-0381-root *::after{box-sizing:border-box}.fx-0381-root{--text-muted:#8b8b93;display:flex;align-items:center;justify-content:center;width:100%;height:250px;overflow:hidden;position:relative;background:rgb(26,26,36);color:rgb(255,255,255);font-family:sans-serif}.gs381-container{width:100%;height:250px;position:relative;overflow:hidden}.gs381-ball{position:absolute;width:30px;height:30px;border-radius:50%;cursor:pointer}.gs381-label{position:absolute;bottom:10px;left:50%;transform:translateX(-50%);font-size:.75rem;color:var(--text-muted);pointer-events:none;z-index:10;white-space:nowrap}
JavaScript (fx-0381)
(function(){var pref=window.matchMedia('(prefers-reduced-motion: reduce)');document.querySelectorAll('.fx-0381-root').forEach(function(root){var container=root.querySelector('.gs381-container');if(!container)return;var balls=[];var gravity=.5,bounce=.7,friction=.99;var rafId=null,lastTs=0;container.addEventListener('click',function(e){var r=container.getBoundingClientRect();var ball=document.createElement('div');ball.className='gs381-ball';ball.style.background='hsl('+(Math.random()*360)+',70%,60%)';var x=e.clientX-r.left-15,y=e.clientY-r.top-15;ball.style.left=x+'px';ball.style.top=y+'px';container.appendChild(ball);balls.push({el:ball,x:x,y:y,vx:(Math.random()-.5)*10,vy:0});if(balls.length>20){var old=balls.shift();old.el.remove()}});container.addEventListener('touchstart',function(e){e.preventDefault();var r=container.getBoundingClientRect();var ball=document.createElement('div');ball.className='gs381-ball';ball.style.background='hsl('+(Math.random()*360)+',70%,60%)';var x=e.touches[0].clientX-r.left-15,y=e.touches[0].clientY-r.top-15;ball.style.left=x+'px';ball.style.top=y+'px';container.appendChild(ball);balls.push({el:ball,x:x,y:y,vx:(Math.random()-.5)*10,vy:0});if(balls.length>20){var old=balls.shift();old.el.remove()}},{passive:false});if(pref.matches)return;function loop(ts){var dt=lastTs>0?Math.min(ts-lastTs,50):16.67;var f=dt/16.67;lastTs=ts;var h=container.offsetHeight,w=container.offsetWidth;balls.forEach(function(b){b.vy+=gravity*f;b.vx*=Math.pow(friction,f);b.x+=b.vx*f;b.y+=b.vy*f;if(b.y>h-30){b.y=h-30;b.vy*=-bounce}if(b.x<0){b.x=0;b.vx*=-bounce}if(b.x>w-30){b.x=w-30;b.vx*=-bounce}b.el.style.left=b.x+'px';b.el.style.top=b.y+'px'});rafId=requestAnimationFrame(loop)}function start(){if(!rafId)rafId=requestAnimationFrame(loop)}function stop(){if(rafId){cancelAnimationFrame(rafId);rafId=null;lastTs=0}}new IntersectionObserver(function(en){en[0].isIntersecting?start():stop()}).observe(root);start()})})();

Personnaliser

Options passées à l'API ou attributs data-* :

Option / propriétéDéfautEffet
Gravité (JS — vy += 0.5 * f) 0,5 px/image² (normalisé 60 fps) 0,2 donne une chute lente ; 1,2 un effet lunaire inversé.
Rebond (JS — vy *= -0.7) 70 % de la vitesse conservée au rebond 0,9 donne des balles qui rebondissent longtemps ; 0,3 un arrêt rapide.
Taille des balles (JS — ball.style.width = ball.style.height = '30px') 30 px Adaptez aussi la détection de sol (b.y + 30 > H).
Palette de couleurs (JS — tableau colors) 5 teintes : violet, rose, indigo, cyan, vert Restreignez à deux couleurs brand ou étendez à sept pour un effet arc-en-ciel.
Hauteur du cadre (CSS — .fx-0381-root { height: 250px }) 250 px Le conteneur intérieur suit automatiquement.

FAQ

Les balles s'accumulent-elles indéfiniment ?

Oui, par défaut. Pour limiter le nombre, ajoutez en début de gestionnaire de clic : if (balls.length >= 30) balls.shift().el.remove();. Cela supprime la plus ancienne balle quand la limite est atteinte.

Peut-on déclencher l'ajout de balles depuis le code, sans clic ?

Oui. La création d'une balle est une simple fonction appelée avec une position {x, y} dans le conteneur. Extrayez-la et appelez-la sur un événement externe : WebSocket, timer, ou réponse à une API.

L'effet marche-t-il dans un cadre plus petit que 250 px ?

Oui, à partir de 80 px de haut environ. En dessous, les balles rebondissent très vite entre le sol et le plafond et donnent un effet chaotique. Adaptez height sur .fx-0381-root et sur .gs381-container.