TR
games/combat-sprite-simulator / site / index.html · commit efee358
<!doctype html><html lang="fr"><head>  <meta charset="utf-8">  <meta name="viewport" content="width=device-width,initial-scale=1">  <meta name="description" content="Combat Sprite Simulator : pilotez un Hurricane au-dessus des photographies aériennes de l'IGN, à partir d'une adresse française.">  <title>Combat Sprite Simulator — Mission à l'adresse</title>  <style>    :root { color-scheme: dark; font-family: system-ui, sans-serif; background: #0a141b; color: #eee; }    * { box-sizing: border-box; }    body { margin: 0; padding: 18px; }    main { max-width: 760px; margin: auto; }    h1 { margin: 0 0 12px; font-size: clamp(22px,4vw,32px); letter-spacing: .07em; text-transform: uppercase; }    form { display: flex; gap: 8px; margin: 12px 0 8px; }    label { display: block; font-weight: 600; }    input { flex: 1; min-width: 0; padding: 13px; font: inherit; background: #152633; border: 1px solid #6b8994; border-radius: 5px; color: #fff; }    button { background: #e2c786; color: #101a1c; border: 0; border-radius: 5px; padding: 0 18px; font-weight: 700; cursor: pointer; }    button:focus-visible, input:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }    #status { color: #b9c9cb; min-height: 1.5em; margin: 0 0 8px; }    .player { display: flex; justify-content: center; background: #03090a; border: 1px solid #344b50; border-radius: 6px; padding: 8px; }    iframe { width: min(100%, 460px); height: min(80vh, 690px); aspect-ratio: 2/3; border: 0; background: #040809; }    .help, footer { color: #b3c4c5; font-size: 13px; line-height: 1.5; }    .help a, footer a { color: #e2c786; }    @media (max-width: 440px) { body { padding: 8px; } form { flex-wrap: wrap; } button { min-height: 42px; } iframe { height: 66vh; } }  </style></head><body>  <main>    <h1>Combat Sprite Simulator</h1>    <label for="address">Choisissez le théâtre de vos combats en France métropolitaine</label>    <form id="flight-form">      <input id="address" type="search" autocomplete="street-address" maxlength="180"        placeholder="Rue, commune, code postal..." aria-describedby="status" required>      <button type="submit">Combattre ici</button>      <button id="free-flight" type="button">Survol libre</button>    </form>    <p id="status" aria-live="polite">Chargement du moteur JumPHP…</p>    <div class="player">      <iframe id="game" src="play/" title="Combat Sprite Simulator — jeu JumPHP"        allow="fullscreen; autoplay" loading="eager"></iframe>    </div>    <p class="help">      « Combattre ici » déclenche les vagues de Bf 109, les Stuka puis le boss Junkers G 38      au-dessus des vraies photographies IGN de l'adresse choisie.      « Survol libre » permet de découvrir les lieux sans ennemis.      La recherche et la simulation sont exécutées en PHP dans JumPHP ; cette page ne fait que transmettre la saisie.    </p>    <footer>      Fond aérien : © IGN — BD ORTHO® (Géoplateforme WMTS).      Les photographies montrent le territoire réel, pas les conditions historiques des combats.      <a href="play/">Ouvrir le jeu seul</a>.    </footer>  </main>  <script>    const game = document.getElementById('game');    const form = document.getElementById('flight-form');    const status = document.getElementById('status');    const field = document.getElementById('address');    let ready = false;    let pending = null;    function sendAddress(address, mode = 'mission') {      try {        const bridge = game.contentWindow?.JumPHP;        if (!ready || typeof bridge?.send !== 'function') {          pending = { address, mode };          status.textContent = 'Le jeu termine son chargement…';          return;        }        bridge.send(mode === 'flight' ? 'fly-to-address' : 'mission-at-address', { address });        pending = null;        status.textContent = (mode === 'mission' ? 'Mission' : 'Survol') + ' : ' + address;        game.focus();      } catch (error) {        status.textContent = 'Le jeu doit être hébergé sur la même origine que cette page.';      }    }    form.addEventListener('submit', (event) => {      event.preventDefault();      const address = field.value.trim();      if (address.length < 3) {        status.textContent = 'Saisissez une adresse plus précise.';        return;      }      sendAddress(address, 'mission');    });    document.getElementById('free-flight').addEventListener('click', () => {      const address = field.value.trim();      if (address.length < 3) {        status.textContent = 'Saisissez une adresse plus précise.';        return;      }      sendAddress(address, 'flight');    });    window.addEventListener('message', (event) => {      if (event.source !== game.contentWindow || event.data?.type !== 'jumphp:ready') return;      ready = true;      status.textContent = 'Prêt : saisissez une adresse ou utilisez le menu du jeu.';      if (pending) sendAddress(pending.address, pending.mode);    });  </script></body></html>