Logo de l'application mobile GeoGaming

Application GeoGaming

(22843)

Créer un mini-jeu auto-contenu (HTML/CSS/JS dans un seul fichier) jouable sur mobile et intégrable directement dans l’application GeoGaming via un champ embeddedCode (type LONGTEXT).

🧱 1. Règles importantes de base

⚙️ Structure technique

  • Un seul fichier <!DOCTYPE html> contenant HTML, CSS et JS inline.
  • Aucune dépendance externe obligatoire (librairie CDN autorisée si le jeu reste fonctionnel sans).
  • Responsive mobile : utilise clamp() pour tailles et espacements.
  • Doit fonctionner dans une iframe ou WebView sans bloquer le scroll de la page parente.
  • Pas d’images externes fragiles → préfère SVG inline ou emojis.
  • Pas de boucle infinie sans setTimeout ou requestAnimationFrame.
  • Éviter les alert()/prompt(), qui bloquent la WebView.

🪣 Communication avec GeoGaming

Quand le joueur termine le jeu, le bouton “Continuer” doit envoyer :

window.postMessage({

  completed: true,

  showModal: false,

  activityKey: « nom-du-jeu », // stable, kebab-case

  points: 2000,              // score final (entier >= 0)

  data: answers              // optionnel : objet contenant les réponses

}, « * »);

Si tu collectes des réponses :

const answers = { q1: « Oui », q2: « … » };

🕹️ Bouton “Passer”

  • Toujours visible dès le début.

  • Affiche une confirmation avant de quitter.

  • Envoie 0 point et pas de modale de fin :

window.postMessage({

  completed: true,

  showModal: false,

  activityKey: « nom-du-jeu »,

  points: 0

}, « * »);

💡 2. Conseils et bonnes pratiques

📱 Événements tactiles (mobile first)

  • Favoriser touchstart ou pointerdown plutôt que click,
    car les événements click ont un léger délai sur mobile et sont moins réactifs.
    Exemple :

element.addEventListener(‘pointerdown’, handleTap);

// ou fallback :

element.addEventListener(‘touchstart’, handleTap, { passive: true });

  • Si tu veux compatibilité totale, fais :

element.addEventListener(‘pointerdown’, handleTap);

element.addEventListener(‘click’, handleTap);

 

🎨 Design et ergonomie

  • Style épuré, clair et fun.
  • Éléments interactifs ≥ 48×48 px (recommandation Google/Apple).
  • Animations simples : transform, opacity, scale.
  • Utilise un conteneur racine (ex. .gg-root) pour isoler ton CSS.
  • Ne bloque jamais le scroll global (overflow:hidden sur body → ❌).

📱 Bonnes pratiques mobile

  • Utilise pointerdown au lieu de click pour la réactivité.
  • Active { passive: true } sur les écouteurs touchstart pour de meilleures perfs.
  • Évite les interactions complexes type drag sur mobile si non indispensables.
  • Teste toujours sur un vrai écran tactile avant validation.

 

📦 Variables CSS conseillées

:root {

  –gg-radius: 20px;

  –gg-card-bg: rgba(0,0,0,.75);

  –gg-card-brd: rgba(255,255,255,.25);

  –gg-shadow: 0 10px 30px rgba(0,0,0,.35);

  –gg-gap: clamp(10px, 3vw, 16px);

  –gg-pad: clamp(12px, 3.5vw, 20px);

  –gg-font: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;

  –gg-primary: #3478f6;

  –gg-success: #4caf50;

  –gg-danger: #e53935;

  –gg-gold: #ffd700;

}

🧠 Accessibilité

  • Contrastes lisibles et tailles de police dynamiques (clamp()).
  • Focus visibles (outline ou box-shadow doux).
  • Actions clavier (Enter/Space) si pertinent.

⚠️ À éviter absolument

  • overflow:hidden sur html, body
  • position: fixed plein écran sans fermeture propre
  • Autoplay audio avant interaction
  • eval() ou appels réseau
  • Ressources hébergées ailleurs sans garantie de persistance

🧩 3. Exemple complet minimal — “Tap to Catch”

Un mini-jeu où le joueur tape sur une cible plusieurs fois pour gagner des points.
Utilise pointerdown pour être fluide sur mobile, et envoie le résultat à GeoGaming.

<!DOCTYPE html><html lang= »fr »><head>

<meta charset= »utf-8″><meta name= »viewport » content= »width=device-width,initial-scale=1″/>

<title>Mini-jeu GeoGaming Tap to Catch</title>

<style>

:root{

  –gg-radius:20px;–gg-card-bg:rgba(0,0,0,.75);–gg-card-brd:rgba(255,255,255,.25);

  –gg-shadow:0 10px 30px rgba(0,0,0,.35);–gg-gap:clamp(10px,3vw,16px);

  –gg-pad:clamp(12px,3.5vw,20px);–gg-font:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;

  –gg-primary:#3478f6;–gg-danger:#e53935;–gg-gold:#ffd700;

}

body{margin:0;font-family:var(–gg-font);color:#fff;}

.gg-scene{padding:clamp(8px,2vw,24px);display:flex;justify-content:center;align-items:center;}

.gg-wrap{width:min(920px,96vw);min-height:min(86vh,900px);background:var(–gg-card-bg);

  border:1px solid var(–gg-card-brd);border-radius:var(–gg-radius);box-shadow:var(–gg-shadow);

  display:flex;flex-direction:column;overflow:auto;}

.gg-row{display:flex;justify-content:space-between;align-items:center;padding:var(–gg-pad);}

.gg-btn{border:0;border-radius:999px;font-weight:700;padding:clamp(12px,3vw,16px) clamp(24px,6vw,32px);

  cursor:pointer;transition:transform .1s;}

.gg-btn–primary{background:var(–gg-primary);color:#fff;}

.gg-btn–danger{background:var(–gg-danger);color:#fff;}

.gg-btn:hover{transform:translateY(-2px);}

.gg-play{flex:1;display:flex;align-items:center;justify-content:center;}

.gg-target{width:64px;height:64px;border-radius:50%;background:#fff;color:#000;

  display:grid;place-items:center;user-select:none;}

.gg-modal{position:fixed;inset:0;display:none;align-items:center;justify-content:center;

  background:rgba(0,0,0,.75);backdrop-filter:blur(6px);z-index:1000;}

.gg-modal__card{width:min(90vw,460px);background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);

  border-radius:24px;text-align:center;padding:clamp(28px,6vw,48px);}

.gg-points{font-size:clamp(2rem,6vw,2.6rem);font-weight:800;color:var(–gg-gold);margin:.6rem 0;}

</style>

</head><body>

<div class= »gg-scene »>

  <div class= »gg-wrap »>

    <div class= »gg-row »>

      <div id= »gg-hud »>Score : <strong id= »gg-score »>2000</strong></div>

      <button id= »gg-skip » class= »gg-btn gg-btn–danger »>Passer</button>

    </div>

    <div class= »gg-play » id= »gg-play »><div class= »gg-target » id= »target »>🎯</div></div>

  </div>

</div>

 

<div class= »gg-modal » id= »gg-end »>

  <div class= »gg-modal__card »>

    <h2>Bravo !</h2>

    <div class= »gg-points » id= »gg-points »>2000 points</div>

    <p>Tu as terminé l’activité.</p>

    <button id= »gg-continue » class= »gg-btn gg-btn–primary »>Continuer</button>

  </div>

</div>

 

<script>

(() => {

  const activityKey = « tap-to-catch »;

  let points = 2000;

  const $ = s => document.querySelector(s);

  const scoreEl = $(‘#gg-score’), target = $(‘#target’),

        play = $(‘#gg-play’), modal = $(‘#gg-end’), pts = $(‘#gg-points’);

 

  let taps=0, max=5;

  function move() {

    const r=play.getBoundingClientRect(), s=64;

    const x=Math.random()*(r.width-s), y=Math.random()*(r.height-s);

    target.style.transform=`translate(${x}px,${y}px)`;

  }

  move();

 

  // Pointerdown = plus fluide sur mobile

  const handleTap = () => {

    taps++; points+=200; scoreEl.textContent=points;

    taps>=max?end():move();

  };

  target.addEventListener(‘pointerdown’, handleTap);

 

  function end(){

    pts.textContent=points+ » points »;

    modal.style.display=’flex’;

  }

 

  $(‘#gg-continue’).addEventListener(‘click’,()=>window.postMessage({

    completed:true,showModal:false,activityKey,points

  }, »* »),{once:true});

 

  $(‘#gg-skip’).addEventListener(‘click’,()=>{

    if(confirm(« Voulez-vous quitter ? »))

      window.postMessage({completed:true,showModal:false,activityKey,points:0}, »* »);

  });

})();

</script>

</body></html>

En résumé :

  • Utilise pointerdown sur mobile.
  • Garde une interface simple et légère.
  • Envoie ton postMessage uniquement à la fin.
  • Et teste toujours sur un vrai écran tactile avant de valider ton jeu.

🤖 4. Assistant ChatGPT 

https://chatgpt.com/g/g-68f232db601c8191bfaa74a7c96d3df3-creation-de-mini-jeu-v2