Essayez gratuitement ! 🍜
Un fichier SCORM intégré dans Soba LMS

Comment créer un fichier SCORM de zéro ?

Ecrit le 04/08/2024

Les fichiers SCORM sont devenus un format incontournable pour partager du contenu e-learning sur les LMS. Le SCORM est un standard créé au début des années 2000. Il est toujours très répandu, malgré la création de nouveaux standards plus modernes et le fait que chaque LMS implémente ce standard un peu différemment.

Nous allons voir dans cet article comment en créer un de zéro.

⚠️ Cet article s'adresse à des développeurs, ou du moins des gens qui aiment mettre les mains dans le cambouis !

Pourquoi créer un fichier SCORM à la main ?

Pas mal de sites et d’outils existent aujourd’hui pour créer des fichiers SCORM en ligne, alors pourquoi s’embêter ?

Effectivement, si vous voulez faire un quiz ou une suite de pages qui se suivent, le faire à la main n’est probablement pas très utile. Mais si vous voulez faire quelque chose qui sort un peu des SCORMs basiques, il va falloir se retrousser les manches !

SCORM est-il le meilleur choix pour vous ?

Je vais vous répondre ce que tout bon développeur répondrait : ça dépend.

En fonction de vos besoins, il vaudrait mieux utiliser un standard plus moderne comme xAPI, ou simplement intégrer dans votre LMS une iframe qui pointe vers un de vos serveurs.

Mais là, nous encapsulons tout notre code dans un gros fichier SCORM, qui sera autonome et qui remontera automatiquement les notes dans notre LMS préféré.

De quoi est composé un fichier SCORM ?

Un fichier SCORM est un fichier zip, qui contient votre code et des méta-informations sous format XML. La plupart de ces méta-informations sont optionnelles, nous allons donc aller au plus simple !

1ère étape : Préparer votre code

Nous allons proposer à nos étudiants une réplique du jeu RoboZZle, codé avec Blockly pour nous simplifier le travail.

Nous allons partir de ce code-là :

Robozzle.zip

Les mécaniques du jeu ne sont pas vraiment implémentées, mais ça nous suffira pour notre test. Si on lance level_1.html, on peut voir que le jeu fonctionne.

2ème étape : Ajouter les méta-informations à votre fichier SCORM

Nous allons ajouter un fichier imsmanifest.xml qui contiendra le minimum d’informations possible pour que notre fichier SCORM fonctionne.

1
<?xml version="1.0" standalone="no" ?>
2
<manifest identifier="robozzle" version="1"
3
          xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"
4
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5
          xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_v1p3"
6
          xmlns:adlseq="http://www.adlnet.org/xsd/adlseq_v1p3"
7
          xmlns:adlnav="http://www.adlnet.org/xsd/adlnav_v1p3"
8
          xmlns:imsss="http://www.imsglobal.org/xsd/imsss"
9
          xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1 imscp_v1p1.xsd
10
                              http://www.adlnet.org/xsd/adlcp_v1p3 adlcp_v1p3.xsd
11
                              http://www.adlnet.org/xsd/adlseq_v1p3 adlseq_v1p3.xsd
12
                              http://www.adlnet.org/xsd/adlnav_v1p3 adlnav_v1p3.xsd
13
                              http://www.imsglobal.org/xsd/imsss imsss_v1p0.xsd">
14
15
  <metadata>
16
    <schema>ADL SCORM</schema>
17
    <schemaversion>2004 3rd Edition</schemaversion>
18
  </metadata>
19
20
  <organizations default="robozzle">
21
    <organization identifier="robozzle" adlseq:objectivesGlobalToSystem="false">
22
      <title>Robozzle</title>
23
      <item identifier="lvl_1" identifierref="lvl_1_resource">
24
        <title>Level 1</title>
25
      </item>
26
    </organization>
27
  </organizations>
28
29
  <resources>
30
    <resource identifier="lvl_1_resource" type="webcontent" adlcp:scormType="sco" href="level_1.html">
31
      <file href="level_1.html"/>
32
      <dependency identifierref="common_files"/>
33
    </resource>
34
    <resource identifier="common_files" type="webcontent" adlcp:scormType="asset">
35
      <file href="robozzle.css"/>
36
      <file href="robozzle.js"/>
37
    </resource>
38
  </resources>
39
</manifest>

Le bloc organizations contient tous les item de notre jeu. Un fichier SCORM peut contenir plusieurs items, ce qui se traduit habituellement par un menu à côté du SCORM, une fois intégré sur le LMS. On peut imaginer cela comme différentes sections. Nous allons, pour l’instant, ignorer cette fonctionnalité et passer à la suite.

Le bloc resources contient toutes les resources de notre jeu. Pour chaque item (le lien entre item et resource est fait grâce au champ identifierref), nous allons préciser le fichier à exécuter (grâce au champ href), ainsi que les fichiers utilisés.

3ème étape : Compresser votre fichier SCORM

Comme nous l’avons dit plus tôt, un fichier SCORM est avant tout un fichier zip. Attention, le fichier imsmanifest.xml doit forcément être à la racine du zip, pas dans un dossier.

Il faut donc sélectionner les différents fichiers utiles et les compresser (contrairement à sélectionner un dossier où tous vos fichiers se trouvent et compresser ce dossier).

Pour tester si notre fichier SCORM fonctionne, nous allons utiliser Soba LMS. Mais vous pouvez utiliser le LMS que vous voulez, comme Moodle par exemple.

Après avoir créé un parcours et ajouté un projet, nous pouvons mettre notre SCORM en 1ère section de ce projet. Et voilà ! Notre mini-jeu est en ligne sur notre LMS !

Un fichier SCORM intégré dans Soba LMS

Communication entre le fichier SCORM et le LMS

Le standard SCORM établit également des règles pour la communication entre le LMS et le fichier SCORM. Cette communication passe par l’objet JavaScript window.parent.API_1484_11 (entre autres, c’est toujours compliqué avec SCORM !).

Cet objet est passé au code JavaScript contenu dans le fichier SCORM, et ce code est utilisé pour passer des pairs “clé/valeur”. Par exemple, vous pouvez passer la clé “lvl” (en vrai, cmi.suspend) avec la valeur “3” pour indiquer que l’utilisateur est passé au niveau 3.

Une série de clés déjà définies permet au LMS d’agir en fonction de certains événements ou de passer au fichier SCORM des données standardisées.

Intégrer la communication avec le LMS

Nous allons modifier notre code pour utiliser window.parent.API_1484_11. Tout d’abord, nous allons initialiser l’objet au début du code. Puis nous allons envoyer cmi.completion_status à completed pour indiquer que le niveau a été réussi.

Nous allons également envoyer puis récuperer la clé cmi.suspend qui contiendra l’état du jeu à la fin. Cela sera pratique à des fins de statistiques pour voir le résultat des étudiants, et on en profitera pour réafficher l’état du jeu à l’étudiant s’il rafraîchit la page.

Enfin, nous allons envoyer la valeur cmi.exit à suspend. Cela sert à demander au LMS de ne pas traiter chaque chargement de la page comme une nouvelle tentative, mais comme la même. Normalement, nous devrions la définir au bon moment (avant de quitter la page par exemple), mais pour simplifier, nous allons l’envoyer dès le début.

1
  window.parent.API_1484_11.Initialize("");
2
  window.parent.API_1484_11.SetValue("cmi.exit", "suspend");
3
4
  const workspace    = Blockly.inject('blocklyDiv', {toolbox: document.getElementById('toolbox'), zoom: {startScale: 1.3}});
5
  const orientations = ['right', 'bottom', 'left', 'top']
6
  const base         = robozzle.outerHTML
7
  let timeout_id     = null
8
9
10
  let xml = window.parent.API_1484_11.GetValue("cmi.suspend_data");
11
  if (xml != "") {
12
    let dom = Blockly.Xml.textToDom(xml);
13
    Blockly.mainWorkspace.clear();
14
    Blockly.Xml.domToWorkspace(Blockly.mainWorkspace, dom);
15
  }
16
17
  workspace.addChangeListener((event) => {
18
    if (event.type == Blockly.Events.BLOCK_MOVE) {
19
      let xmlDom      = Blockly.Xml.workspaceToDom(Blockly.mainWorkspace);
20
      let xmlText     = Blockly.Xml.domToPrettyText(xmlDom);
21
22
      window.parent.API_1484_11.SetValue("cmi.suspend_data", xmlText);
23
      window.parent.API_1484_11.Commit("")
24
    }
25
  })
26
27
28
  async function __end_action() {
29
    if (document.querySelector('.robot.outside')) {
30
      alert('Perdu');
31
32
      return false
33
    }
34
35
    document.querySelector('.robot.star')?.classList?.remove('star')
36
37
    if (document.querySelector('.star') == undefined) {
38
      alert('Gagné !');
39
40
      window.parent.API_1484_11.SetValue("cmi.completion_status", "completed");
41
      window.parent.API_1484_11.Commit("");
42
      window.parent.API_1484_11.Terminate("");
43
44
      return false
45
    }
46
47
    await new Promise((resolve) => setTimeout(resolve, 500))
48
49
    return true
50
  }

Il ne reste plus qu’à appeler les méthodes Commit (pour signifier que les SetValue doivent être sauvegardés sur le LMS) et Terminate pour couper la connexion avec le LMS.

Gérer plusieurs niveaux

Nous avons plusieurs possibilités pour avoir plusieurs niveaux. Mais c’est à partir de maintenant que les LMS divergent un peu sur comment suivre le standard SCORM. Mais on va s’en sortir !

Option 1 : Utiliser le système d'items du `imsmanifest.xml`

Comme nous l’avons vu plus tôt, un fichier imsmanifest.xml peut avoir plusieurs items. Chaque item sera représenté comme une section différente du fichier SCORM.

⚠️ Vous verrez des différences de gestion entre Moodle, Soba (ainsi que d'autres LMS !).

Après modification, notre fichier imsmanifest.xml ressemble à ça :

1
<?xml version="1.0" standalone="no" ?>
2
<manifest identifier="robozzle" version="1"
3
          xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"
4
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5
          xmlns:adlcp="http://www.adlnet.org/xsd/adlcp_v1p3"
6
          xmlns:adlseq="http://www.adlnet.org/xsd/adlseq_v1p3"
7
          xmlns:adlnav="http://www.adlnet.org/xsd/adlnav_v1p3"
8
          xmlns:imsss="http://www.imsglobal.org/xsd/imsss"
9
          xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1 imscp_v1p1.xsd
10
                              http://www.adlnet.org/xsd/adlcp_v1p3 adlcp_v1p3.xsd
11
                              http://www.adlnet.org/xsd/adlseq_v1p3 adlseq_v1p3.xsd
12
                              http://www.adlnet.org/xsd/adlnav_v1p3 adlnav_v1p3.xsd
13
                              http://www.imsglobal.org/xsd/imsss imsss_v1p0.xsd">
14
15
  <metadata>
16
    <schema>ADL SCORM</schema>
17
    <schemaversion>2004 3rd Edition</schemaversion>
18
  </metadata>
19
20
  <organizations default="robozzle">
21
    <organization identifier="robozzle" adlseq:objectivesGlobalToSystem="false">
22
      <title>Robozzle</title>
23
24
      <item identifier="lvl_1" identifierref="lvl_1_resource">
25
        <title>Level 1</title>
26
      </item>
27
      <item identifier="lvl_2" identifierref="lvl_2_resource">
28
        <title>Level 2</title>
29
      </item>
30
    </organization>
31
  </organizations>
32
33
  <resources>
34
    <resource identifier="lvl_1_resource" type="webcontent" adlcp:scormType="sco" href="level_1.html">
35
      <file href="level_1.html"/>
36
      <dependency identifierref="common_files"/>
37
    </resource>
38
    <resource identifier="lvl_2_resource" type="webcontent" adlcp:scormType="sco" href="level_2.html">
39
      <file href="level_2.html"/>
40
      <dependency identifierref="common_files"/>
41
    </resource>
42
    <resource identifier="common_files" type="webcontent" adlcp:scormType="asset">
43
      <file href="robozzle.css"/>
44
      <file href="robozzle.js"/>
45
    </resource>
46
  </resources>
47
</manifest>

Nous avons ajouté un item et un resource pour notre 2ème niveau. Une fois uploadé sur Soba, notre jeu ressemble à ça :

Un fichier SCORM avec plusieurs sections intégré dans Soba LMS

Une fois au niveau 2, on peut rafraîchir la page et voir que Soba nous amène directement au niveau 2.

Option 2 : Laisser le code JS du fichier SCORM gérer les niveaux

Comme nous l’avons vu, nous pouvons communiquer les données que nous voulons au LMS, et il nous les renverra au prochain affichage. Ces données sont propres à chaque utilisateur.

Cela signifie qu’en modifiant notre code JS (on ne le fera pas là, je vous laisse cela comme exercice !), on peut lui faire afficher le niveau qui correspond au niveau actuel de l’apprenant. Ainsi, tous les LMS réagiront de manière identique !

Option 3 : Stocker les résultats sur un autre serveur

Le LMS devrait vous fournir des informations qui identifient l’apprenant qui affiche le fichier SCORM. Par exemple, la variable cmi.learner_id sert à identifier de manière unique l’apprenant.

En utilisant ces variables, il est possible de stocker le résultat d’un apprenant sur un autre serveur et ainsi lui afficher son niveau en cours quand il se reconnecte.

Conclusion

La création d’un fichier SCORM basique n’est finalement pas très complexe. Il suffit d’ajouter un fichier XML et de communiquer avec le LMS via l’objet window.parent.API_1484_11.

Mais créer un fichier SCORM qui suit le standard est, pour le coup, assez compliqué. N’hésitez pas à consulter le site officiel de SCORM et ce wrapper déjà codé, qui vous simplifiera la tâche si vous voulez aller plus loin.

On peut outrepasser les limitations de SCORM (ou de ses implémentations) en ayant notre propre serveur pour stocker les résultats.

Nous n’en avons pas parlé dans cet article, mais les niveaux peuvent être envoyés depuis notre autre serveur, et ainsi, on peut corriger/ajouter des niveaux à la volée, sans changer le fichier SCORM qui a été uploadé sur notre LMS.

🍜

Explorez les fonctionnalités clés de Soba LMS (on gère bien plus que les fichiers SCORM !), ou testez-les gratuitement et découvrez comment Soba LMS peut répondre à vos besoins !


Vous aimerez aussi lire :