escape-game-360-maker

Selector v1 — Spécification (brouillon cible)

Document de travail pour le futur type de hotspot selector (menu de choix, sous-menus, options conditionnelles, SFX par choix).
Rien de ce qui suit n’est encore implémenté dans le code : c’est le cahier des charges pour le refactor prévu.

Pour le contexte général du projet, voir ARCHITECTURE.md.


1. Objectifs

Rétrocompatibilité JSON : non requise pour ce projet au moment du refactor (usage principal = auteur seul, anciens fichiers surtout POC). Un schéma JSON v2 peut donc casser l’ancien format si cela simplifie le code ; documenter une procédure de migration manuelle ou un script reste utile pour qui aurait gardé d’anciens .json.


2. Principes d’architecture (jeu généré)

Couche Rôle
hotspotDispatcher(hsDiv, args) Point d’entrée Pannellum. Si args.type === 'selector' → ouvrir l’UI selector ; sinon → executeAction(...).
executeAction(payload, hsDiv, uiContext) Exécute une action unique (message, changement de scène, ramassage, requis, passcode, etc.).
openSelector(selectorArgs, uiContext) Affiche une seule surface modale ; le contenu (titre, intro, liste de choix) est remplacé quand on descend dans un sous-menu ou qu’on revient en arrière. Pas d’empilement de plusieurs popups les unes sur les autres — uniquement une pile logique (historique) pour le bouton Retour.
evaluateChoiceVisibility(choice, gameState) (Optionnel v1) Décide si un choix est visible / activé selon l’inventaire ou d’autres états.

Contexte partagé : inventaire, scène courante, états de déverrouillage, etc. Les sous-selectors héritent du même état global (pas de “sandbox” séparé sauf besoin futur explicite).

Anti double-clic : tant qu’un selector (ou une popup modale dérivée) est ouvert, les interactions sur le panorama / autres hotspots sont bloquées (overlay plein écran ou équivalent), pour éviter les clics en cascade.


3. Modèle de données (JSON projet / args générés)

3.1 Hotspot selector (schéma cible)

Champs communs avec les autres types : pitch, yaw, cssClass, type: "selector".

Payload minimal :

{
  "type": "selector",
  "id": "hs_uid_…",
  "title": "Terminal",
  "introHtml": "<p>Écran d’accueil…</p>",
  "choices": [
    {
      "id": "choice_1",
      "label": "Lire les mails",
      "actionType": "selector",
      "nested": {
        "title": "Boîte mail",
        "introHtml": "",
        "choices": [
          { "id": "m1", "label": "Mail 1", "actionType": "msg", "txt": "…" },
          { "id": "m2", "label": "Mail 2", "actionType": "msg", "txt": "…" }
        ]
      }
    },
    {
      "id": "choice_2",
      "label": "Désactiver l’alarme",
      "actionType": "pwd",
      "enigmeTxt": "…",
      "pwd": "1234",
      "onSuccess": { "actionType": "scene", "target": "couloir" }
    }
  ]
}

3.2 Champs par choice (tous optionnels sauf label + branche action)

Champ Usage
label Texte du bouton ou entrée de liste.
actionType msg | scene | pick | req | pwd | selector
requiresItem (Optionnel) ID d’objet : le choix n’apparaît que si l’inventaire contient cet ID.
hiddenIfHasItem (Optionnel) ID d’objet : le choix est masqué si le joueur possède cet objet.
sfxUrl URL du son au clic sur ce choix (optionnel).
sfxVolume 0–1, relatif au canal SFX du joueur (sfxVol × masterVol).
displayMode Sur un niveau (nested ou racine via l’éditeur) : buttons (défaut) ou dropdown.

Les autres champs reprennent la même sémantique que les champs actuels des hotspots (ex. txt, target, itemId, ko, transTxt, etc.) pour que executeAction reste unique.

3.3 Équivalence “hotspot classique = selector à un choix”

Conceptuellement :

En implémentation v1 on peut garder les types existants dans l’éditeur et ne pas forcer la migration visuelle ; la factorisation interne se fait côté runtime (executeAction).


4. UI / UX

4.1 Présentation des choix

4.2 Navigation

4.3 Fermeture après une action “feuille”

4.3 bis — Inventaire « pick » et visibilité future

4.4 Options conditionnelles (inventaire / état)

Les deux sont compatibles avec le même schéma si evaluateChoiceVisibility est bien défini.


5. Côté éditeur (à implémenter plus tard)


6. Migration et compatibilité


7. Ordre d’implémentation recommandé

  1. Refactor jeu généré uniquement : extraire executeAction depuis la logique actuelle de hotspotDispatcher + executeReward ; valider avec des scénarios de test (anciens POC optionnels). Fait (template dans js/editeur-generate.js / js/editor-en-generate.js).
  2. Ajouter openSelector minimal (liste de boutons, un niveau, pas d’imbrication). Fait : overlay plein écran (#selector-overlay), une modale, boutons ; choiceToPayloadexecuteAction pour msg / scene / pick.
  3. Étendre JSON + éditeur pour éditer choices simples. Partiel : type selector + titre / intro / textarea JSON des choix (édition avancée) ; à remplacer plus tard par un formulaire guidé (ajout/suppression de lignes, etc.).
  4. Ajouter Retour, imbrication Fait ; visibilité conditionnelle (requiresItem, hiddenIfHasItem), liste déroulante (displayMode), SFX (sfxUrl, sfxVolume + audioSys.playSFX) Fait (joueur + option éditeur « Liste déroulante » ; champs JSON documentés dans l’UI).
  5. Découpage fichiers (player.js / modules) une fois le comportement stable.

8. Références croisées