> ## Knowledge Base Index
> Fetch the complete knowledge base index at: https://documentation.celestory.io/sitemap.xml
> Use this file to discover available pages before exploring further.
> Pure-Markdown content can be obtained by appending a '.md' suffix to the content URLs listed in the sitemap (without the trailing slash).

# Écrire une page HTML5 dans Celestory

# 🧑‍💻 Écrire une page HTML5 dans Celestory

Le bloc **HTML5** est la porte de sortie de Celestory. Vous y collez une page web complète — HTML, CSS, JavaScript — et Celestory l'affiche plein écran à ce moment du parcours. Un mini-jeu, un formulaire sur mesure, une simulation, un canevas dessiné à la main : tout ce pour quoi il n'existe pas de bloc.

Mais une page isolée ne sert à rien. Ce qui compte, c'est le **contrat** : comment la page reçoit des valeurs du graphe, et comment elle lui en rend. Il tient en trois éléments. 🔌

🔺 Le bloc **HTML5** demande un abonnement **Business**.

---

## 📝 Où l'on écrit, et quand c'est enregistré

Ouvrez le bloc **HTML5** (double-clic). Son entrée **contenu** accueille un éditeur de code complet — le moteur de Visual Studio Code — avec coloration syntaxique et repli de blocs.

🔺 **Votre code n'est transmis au graphe qu'à la perte du focus.** Tant que le curseur clignote dans l'éditeur, Celestory ne voit rien. Cliquez en dehors de l'éditeur, ou fermez la fenêtre d'édition du bloc : c'est **à cet instant** que le code est enregistré et que les points d'entrée et de sortie apparaissent ou disparaissent sur le bloc.

C'est la source de confusion numéro un. Si vous venez de coller un `{{prenom}}` et qu'aucune entrée n'apparaît, vous n'avez simplement pas encore quitté l'éditeur. 🙂

La page doit être **autonome** : rien n'est empaqueté à côté d'elle, aucun fichier voisin n'est servi. Tout ce dont elle a besoin tient dans le bloc, ou se charge depuis une URL publique.

---

## 📥 Recevoir des valeurs : les doubles accolades

Écrivez `{{nom}}` **n'importe où dans le code**, et Celestory crée une entrée de ce nom sur le bloc.

```html
<h1>Bonjour {{prenom}} !</h1>
<p>Vous en êtes à {{score}} points.</p>
```

Deux entrées apparaissent : `prenom` et `score`. Branchez-y une variable, la sortie d'un autre bloc, ou saisissez une valeur en dur. Elles acceptent du **Texte**, un **Nombre** ou un **Booléen**.

🔺 **Seules les lettres non accentuées, les chiffres et le tiret bas sont acceptés** : `a-z`, `A-Z`, `0-9`, `_`. `{{Prénom}}`, `{{mon-score}}` et `{{ prenom }}` ne sont **pas** détectés. Aucune entrée n'est créée, aucune erreur n'apparaît, et le repère s'affiche tel quel à l'écran. La casse compte. Ce sont exactement les règles de l'article **Les doubles accolades**.

🔺 **Le remplacement est purement textuel**, effectué dans le code source avant que la page ne s'exécute. En JavaScript, un texte doit donc porter ses guillemets :

```html
<script>
  const points = {{score}};        // ✅ un nombre, tel quel
  const joueur = "{{prenom}}";     // ✅ un texte, entre guillemets
  const casse  = {{prenom}};       // ❌ erreur de syntaxe à l'exécution
</script>
```

🔺 Une entrée **non branchée** est remplacée par **du vide**. `const points = ;` : votre page ne démarre pas, et rien ne vous prévient.

---

## 📤 Renvoyer des valeurs : déclarer, puis poster

C'est le point le moins évident, et il se fait en deux temps.

### 1. Déclarer ce que la page rendra

Écrivez ce commentaire n'importe où dans la page :

```html
<!-- celestory-outputs: score, verdict -->
```

Chaque nom listé devient une **sortie** sur le bloc, que vous pouvez lire, tester ou brancher comme n'importe quelle autre. Séparez-les par des virgules ou des espaces, sur une ligne ou sur plusieurs. Ces sorties acceptent du **Texte**, un **Nombre** ou un **Booléen**.

🔺 Les mêmes règles de nommage s'appliquent : lettres non accentuées, chiffres, tiret bas. Rien d'autre.

### 2. Poster la valeur pendant que la page tourne

```html
<script>
  parent.document.dispatchEvent(
    new CustomEvent('CelestoryOutput', {detail: {key: 'score', value: 42}})
  );
</script>
```

Le `key` désigne la sortie, le `value` la valeur. Postez autant de fois que vous voulez : la dernière valeur postée pour une clé donnée est celle que le graphe lira.

Il existe une **seconde voie**, plus ancienne mais toujours active : si la clé est écrite **littéralement** dans l'appel, comme ci-dessus, Celestory la repère à la lecture du code et crée la sortie, même sans commentaire de déclaration.

🔺 Mais dès que la clé est calculée — `key: nomDeLaSortie` — plus rien n'est détecté. **Déclarez toujours vos sorties dans le commentaire.** C'est la seule méthode qui ne dépende pas de la façon dont vous écrivez votre code.

---

## 🏁 Rendre la main au graphe : CelestoryEnd

Tant que la page est à l'écran, le parcours est arrêté. Pour le relancer, la page envoie :

```html
<script>
  parent.document.dispatchEvent(new CustomEvent('CelestoryEnd'));
</script>
```

Le flux repart alors par la sortie **out** du bloc. L'évènement est **idempotent** : envoyez-le dix fois, le graphe n'avance qu'une seule fois.

**Postez vos valeurs avant de terminer.** L'ordre compte : `CelestoryEnd` fait avancer le flux, et les blocs suivants lisent ce qui a été posté jusque-là.

🔺 **Une page qui n'envoie jamais `CelestoryEnd` peut bloquer l'expérience.** Il vous reste le bouton de fermeture, mais il n'apparaît que si la sortie **out** est branchée *et* si l'entrée **bouton fermer** vaut vrai. Sans l'un ni l'autre, le joueur est coincé.

---

## ⚠️ Le piège : les écouteurs sont sur le *document*

C'est confirmé dans le code, et c'est la cause d'échec la plus fréquente : **Celestory écoute sur des `document`, jamais sur une `window`.**

Votre page tourne dans un cadre isolé. Deux écoutes sont posées : une sur le document de l'application qui l'héberge, une sur le document de la page elle-même.

```html
<script>
  // ✅ toujours correct — le document de l'application hôte
  parent.document.dispatchEvent(new CustomEvent('CelestoryEnd'));

  // ✅ correct aussi — le document de votre propre page
  document.dispatchEvent(new CustomEvent('CelestoryEnd'));

  // ❌ n'arrive nulle part, en silence
  window.dispatchEvent(new CustomEvent('CelestoryEnd'));
  parent.dispatchEvent(new CustomEvent('CelestoryEnd'));
  dispatchEvent(new CustomEvent('CelestoryEnd'));
</script>
```

🔺 Envoyer l'évènement à une `window` ne déclenche **rien du tout**, quoi que fasse le reste de votre page. Aucune erreur dans la console, aucun message : la page reste simplement figée.

🔺 Le poster sur un **élément** (un bouton, une `div`) ne marche pas non plus, sauf à le faire remonter explicitement — et un `CustomEvent` ne remonte pas par défaut. **Prenez l'habitude de `parent.document`**, il fonctionne dans tous les cas.

---

## 🧩 Une page complète, de bout en bout

```html
<!-- celestory-outputs: reponse, correct -->
<!DOCTYPE html>
<html>
  <body style="font-family: sans-serif; text-align: center; padding: 40px">
    <h1>Bonjour {{prenom}} !</h1>
    <p>Combien font 7 × 6 ?</p>
    <input id="saisie" type="number" />
    <button id="valider">Valider</button>

    <script>
      document.getElementById('valider').addEventListener('click', () => {
        const valeur = Number(document.getElementById('saisie').value);

        parent.document.dispatchEvent(new CustomEvent('CelestoryOutput',
          {detail: {key: 'reponse', value: valeur}}));
        parent.document.dispatchEvent(new CustomEvent('CelestoryOutput',
          {detail: {key: 'correct', value: valeur === 42}}));

        parent.document.dispatchEvent(new CustomEvent('CelestoryEnd'));
      });
    </script>
  </body>
</html>
```

Sur le bloc, après avoir quitté l'éditeur, vous obtenez :

- une entrée **prenom** à brancher ;
- deux sorties **reponse** (un nombre) et **correct** (un booléen) ;
- la sortie de flux **out**, à brancher sur la suite — un bloc **Condition** sur `correct`, par exemple.

Le type de la sortie suit la valeur postée : un nombre arrive en **Nombre**, un booléen en **Booléen**, tout le reste en **Texte**.

---

## 🧷 Le reste du bloc

L'entrée **bouton fermer** affiche une croix en haut à droite de la page. Elle est active par défaut, et ne sert que de filet de sécurité : cliquer dessus fait exactement ce que ferait `CelestoryEnd`, sans qu'aucune valeur n'ait été postée. Mettez-la à faux pour un mini-jeu dont on ne doit pas pouvoir sortir — à condition que votre page sache se terminer toute seule.

---

## ✅ La liste de contrôle

Avant de tester, vérifiez ces cinq points :

1. Vous avez **quitté l'éditeur** : les points sont bien apparus sur le bloc.
1. Chaque `{{nom}}` est **sans accent** et **branché**.
1. Vos sorties sont **déclarées** dans `<!-- celestory-outputs: … -->`.
1. Tous vos évènements partent sur **`parent.document`**.
1. Votre page envoie **`CelestoryEnd`** — après avoir posté ses valeurs.

---

→ Prochaine étape : partez de la page complète ci-dessus, collez-la dans un bloc **HTML5**, quittez l'éditeur, branchez `prenom` et posez un bloc **Condition** sur la sortie `correct`. Vous tenez le schéma de tous les usages avancés de Celestory.
