escape-game-360-maker

Architecture — Escape Game 360° Maker

This document is for developers and AI assistants working on the repository. End-user instructions stay in the root README.md.

Repository layout

Path Role
editeur.html Main editor (French UI): markup + <link> / <script src>.
editor_en.html Same behavior, English UI; comments in English; default save as project.json.
css/editor.css Shared editor chrome (layout, buttons, modals, form controls).
js/editeur-app.js French editor: UI, scenes/hotspots, save/load, previews — everything except generateGame.
js/editeur-generate.js French: generateGame() (player template) + window.onload boot.
js/editor-en-app.js English editor — same split as FR; mirrors editeur-app.js.
js/editor-en-generate.js English: generateGame() + boot; mirrors editeur-generate.js.
README.md User-facing documentation (FR + EN).

There is no build step. Open either HTML file from disk or host statically (e.g. GitHub Pages). HTML files live at the repo root; assets use relative paths (css/, js/). Load order: *-app.js then *-generate.js (both defer); the second file defines generateGame and window.onload.

Editor shell vs generated player

Each editor page loads:

  1. Editor application — the *-app.js then *-generate.js pair runs in the browser tab; builds the form, preview modals, saves JSON, calls generateGame().
  2. Generated output — not stored in the repo; generateGame() builds a string (htmlTemplate) and triggers download of index.html. That file is a standalone player: Pannellum + inventory + audio + hotspot logic.

Important: the player code is embedded as a large template literal inside generateGame(). Changing gameplay requires editing that template (or later extracting it to a shared script).

Data flow

Form DOM  →  saveProject()  →  projet.json / project.json
projet.json / project.json   →  loadProject()  →  rebuild DOM (addScene, addHotspot)

Form DOM  →  generateGame()  →  index.html (download)
flowchart LR
    A[Editor form DOM] --> B[saveProject]
    B --> C[project JSON file]
    C --> D[loadProject]
    D --> A

    A --> E[generateGame]
    E --> F[index.html download]
    F --> G[Standalone player]
    G --> H[Pannellum viewer]
    G --> I[Inventory + dialogs + audio]

Project JSON (save file)

Top-level keys (see saveProject()):

Each hotspot object is produced by extractHotspotData() — dynamic field names use underscores (e.g. f_trans_txt from class f-trans-txt), plus ui_* for visual CSS editor, expertMode, hsTitle, pitch, yaw, customCss, type.

Editor: main functions (reference)

Function Purpose
addScene / addHotspot Inject scene or hotspot blocks; defaults for new items.
extractHotspotData Serialize one hotspot for JSON or duplication.
duplicateHotspot / duplicateScene Copy helpers; scene duplicate copies ambient URL.
buildCss / toggleExpertMode No-code CSS vs raw textarea.
openPicker / previewScene Fullscreen Pannellum for coordinates / scene preview (#live-preview-styles).
updateHsFields Swap dynamic fields by hotspot type (msg, pick, req, pwd, scene, selector).
saveProject / loadProject JSON persistence.
updatePreview Inventory + dialog preview widgets in global settings.
generateGame Read DOM → build scenesConfig, sceneAudios, CSS, inject into template → download.

Hotspot types in the player are handled in hotspotDispatcher inside the generated script.

Pannellum integration

Hotspots use createTooltipFunc pointing to hotspotDispatcher (a real function in the player). The config is built with JSON.stringify then a string replace converts "createTooltipFunc": "hotspotDispatcher" to a bare identifier so the output is valid JavaScript.

Modales joueur (openSelector, afficherPopup, énigme mot de passe) partagent le même chrome : overlay plein écran assombri (rgba(0,0,0,0.82)), z-index: 10050, panneau centré max-width: 420px, border-radius: 8px, ombre. Clic sur le fond : fermeture (pour afficherPopup, sans appeler onConfirm).

Scene changes: player listens to scenechange and calls applySceneAmbiance(sceneId) so per-scene ambient audio stays aligned with the current room.

Audio (player)

Splash screen exists so audio can start after a user gesture (browser autoplay policies).

Notable DOM hooks

Hosting and CORS

Evolutions (planned / discussed)

These are not fully implemented unless marked otherwise; listed so assistants know intent:

Planned selector refactor (future)

Detailed draft specification: SELECTOR_SPEC.md.

The next major gameplay evolution is a new hotspot type: selector.

Goal:

Why refactor first

Current generated player logic is mostly linear in hotspotDispatcher.
For selectors and nested selectors, action execution should be centralized in one reusable function.

Target architecture

  1. Keep hotspotDispatcher as the trigger layer (Pannellum integration).
  2. executeAction(payload, hsDiv) — implemented in the generated index.html (template in *-generate.js). Handles msg / scene / pick; executeReward delegates req/pwd success branches to the same engine.
  3. Add openSelector(...) for selector UI: one modal container; sub-menus replace inner content (logical history stack only — no stacked popups).
  4. hotspotDispatcher behavior:
    • classic hotspot (msg / scene / pick / req / pwd): executeAction / executeReward / inline pwd UI
    • selector hotspot: openSelector(...) then choiceToPayloadexecuteAction for each choice (msg / scene / pick in v1)
  5. A selector choice click:
    • if actionType !== "selector": call executeAction(...)
    • if actionType === "selector": push next level into the same modal (replace view)
flowchart TD
    A[Hotspot click] --> B{type}
    B -->|classic| C[executeAction payload]
    B -->|selector| D[openSelector same modal]
    D --> E[Choice click]
    E --> F{choice actionType}
    F -->|classic| C
    F -->|selector| D

Data model direction

Current model stays valid for classic hotspot types.
Add selector payload on top:

Implementation notes

Versioning

Feature list for non-developers is maintained in README (bump version there when you ship meaningful changes). This file does not duplicate marketing version numbers unless useful for debugging.