Export Web/SCORM : port complet du runtime jouable côté navigateur
Phase 1.2 de la feuille de route produit — un paquet SCORM tourne seul dans le LMS du client, sans serveur Forge Engine disponible. Ajoute static/js/play/offline/ (miroir JS de screens/rendering/ et data_actions/, sous window.FORGE_OFFLINE) pour que variables, score, données d'objet, répéteurs et conditions de visibilité fonctionnent entièrement en mémoire côté navigateur ; branche actions.js et bindings.js dessus au lieu d'un fetch() serveur. Ajoute publish/build_scorm_package.py (paquet statique + imsmanifest.xml SCORM 1.2 + wrapper API SCORM) et le bouton "Exporter (Web/SCORM)". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
9776fbc057
commit
f3b72d73c9
@@ -252,6 +252,13 @@ function runActionNode(node) {
|
||||
const ms = isNaN(seconds) ? 0 : Math.max(0, seconds) * 1000;
|
||||
return new Promise(function(resolve) { setTimeout(resolve, ms); });
|
||||
} else if (node.action_type === 'modifier_donnee') {
|
||||
// Export Web/SCORM (voir static/js/play/offline/apply-actions.js) :
|
||||
// aucun serveur disponible dans le paquet exporté — la même mutation
|
||||
// s'applique directement sur gameData, en mémoire, dans le navigateur.
|
||||
if (window.FORGE_OFFLINE) {
|
||||
forgeApplyDataActionOffline(gameData, node);
|
||||
return refreshRuntimeData();
|
||||
}
|
||||
const runDataUrl = FORGE_PLAY_URLS.flowNodeRunData.replace('999999', node.id);
|
||||
// clicked_row_id/last_inserted_row_id : utilisés côté serveur
|
||||
// SEULEMENT si ce nœud vise respectivement CLICKED_ROW_ID ou
|
||||
@@ -264,6 +271,10 @@ function runActionNode(node) {
|
||||
.then(r => r.json())
|
||||
.then(() => refreshRuntimeData());
|
||||
} else if (node.action_type === 'modifier_variable') {
|
||||
if (window.FORGE_OFFLINE) {
|
||||
forgeApplyVariableActionOffline(gameData, node);
|
||||
return refreshRuntimeData();
|
||||
}
|
||||
const runVarUrl = FORGE_PLAY_URLS.flowNodeRunVariable.replace('999999', node.id);
|
||||
return fetch(runVarUrl, {method: 'POST'})
|
||||
.then(r => r.json())
|
||||
@@ -271,22 +282,35 @@ function runActionNode(node) {
|
||||
} else if (node.action_type === 'modifier_score') {
|
||||
// Score/progression (voir db/scoring/, screens/data_actions/
|
||||
// apply_score_action.py) : même patron que "Modifier une variable
|
||||
// globale" ci-dessus, calculé et écrit entièrement côté serveur.
|
||||
// globale" ci-dessus, calculé et écrit côté serveur EN LIGNE, ou
|
||||
// directement en mémoire dans le paquet exporté (voir apply-actions.js).
|
||||
if (window.FORGE_OFFLINE) {
|
||||
forgeApplyScoreActionOffline(gameData, node);
|
||||
return refreshRuntimeData();
|
||||
}
|
||||
const runScoreUrl = FORGE_PLAY_URLS.flowNodeRunScore.replace('999999', node.id);
|
||||
return fetch(runScoreUrl, {method: 'POST'})
|
||||
.then(r => r.json())
|
||||
.then(() => refreshRuntimeData());
|
||||
} else if (node.action_type === 'definir_statut_partie') {
|
||||
if (window.FORGE_OFFLINE) {
|
||||
forgeApplyStatusActionOffline(gameData, node);
|
||||
return refreshRuntimeData();
|
||||
}
|
||||
const runStatusUrl = FORGE_PLAY_URLS.flowNodeRunStatus.replace('999999', node.id);
|
||||
return fetch(runStatusUrl, {method: 'POST'})
|
||||
.then(r => r.json())
|
||||
.then(() => refreshRuntimeData());
|
||||
} else if (node.action_type === 'ajouter_ligne') {
|
||||
// Phase 4 — crée une ligne VIDE côté serveur ; son id devient
|
||||
// window.lastInsertedRowId pour que les nœuds "Modifier une donnée"
|
||||
// enchaînés (ciblant LAST_INSERTED_ROW_ID, "➕ Dernière ligne
|
||||
// ajoutée") sachent quelle ligne renseigner. refreshRuntimeData()
|
||||
// affiche la nouvelle ligne dans tout Répéteur lié dès ce round-trip.
|
||||
// Phase 4 — crée une ligne VIDE (côté serveur en ligne, en mémoire
|
||||
// hors ligne) ; son id devient window.lastInsertedRowId pour que les
|
||||
// nœuds "Modifier une donnée" enchaînés (ciblant LAST_INSERTED_ROW_ID,
|
||||
// "➕ Dernière ligne ajoutée") sachent quelle ligne renseigner.
|
||||
// refreshRuntimeData() affiche la nouvelle ligne dans tout Répéteur lié.
|
||||
if (window.FORGE_OFFLINE) {
|
||||
window.lastInsertedRowId = forgeApplyAddRowActionOffline(gameData, node);
|
||||
return refreshRuntimeData();
|
||||
}
|
||||
const runAddRowUrl = FORGE_PLAY_URLS.flowNodeRunAddRow.replace('999999', node.id);
|
||||
return fetch(runAddRowUrl, { method: 'POST' })
|
||||
.then(r => r.json())
|
||||
@@ -418,6 +442,6 @@ function stopAllSpriteAnimations() {
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = {
|
||||
resolveSpriteFrames, runSpriteAnimation, stopAllSpriteAnimations, activeSpriteAnimations,
|
||||
applyObjectProperty, clampSceneObjectPosition,
|
||||
applyObjectProperty, clampSceneObjectPosition, runActionNode,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user