Les Monstres d’Amphitrite 1.1

A l'occasion du premier anniversaire du lancement des Monstres d'Amphitrite, j'y ai enfin apporté un petit correctif qui devrait en améliorer grandement l'ergonomie et en particulier mieux mettre en valeur les deux choix de parcours possibles. Accessoirement, le correctif corrige aussi un bug dans la gestion de l'interruption des effets animés.

Cliquez sur l'image.

Retour de résidence

Après six semaines de résidence, voici l'heure du bilan de cette expérience nouvelle pour moi. Il est, comme on dit pudiquement, "mitigé". J'ai mis en ligne à intervalle irrégulier des comptes-rendus sur les réseaux sociaux durant toute la résidence. Je les retranscris presque tous chronologiquement ci-dessous avant quelques réflexions plus introspectives en guise de conclusion.

Jour 1: Mon lieu de villégiature pour ces prochaines semaines.

img_0094

Jour 5: Quand on teste "quelques paramètres vite fait à la main" parce que ça vaut pas le coup de créer une base de données pour des tests:

<img src='images/11.jpg' id='11' alt='11' data-sc='6' data-f='0' data-a='1' data-t='0'/>
<img src='images/8.jpg' id='8' alt='8' data-sc='4' data-f='0' data-a='0' data-t='1'/>
<img src='images/16.jpg' id='16' alt='16' data-sc='5' data-f='0' data-a='0' data-t='0'/>
<img src='images/5.jpg' id='5' alt='5' data-sc='4' data-f='1' data-a='0' data-t='0'/>
<img src='images/35.jpg' id='35' alt='35' data-sc='6' data-f='1' data-a='0' data-t='0'/>
<img src='images/17.jpg' id='17' alt='17' data-sc='5' data-f='0' data-a='0' data-t='0'/>
<img src='images/21.jpg' id='21' alt='21' data-sc='0' data-f='1' data-a='0' data-t='0'/>
<img src='images/9.jpg' id='9' alt='9' data-sc='2' data-f='0' data-a='0' data-t='0'/>
<img src='images/34.jpg' id='34' alt='34' data-sc='6' data-f='1' data-a='0' data-t='1'/>
<img src='images/27.jpg' id='27' alt='27' data-sc='1' data-f='0' data-a='0' data-t='0'/>

Jour 9: Imaginez un peu, mesdames et messieurs, une bande dessinée dont les cases, déplaçables, échangent tout ou partie de leurs propriétés et contenus lorsqu'elles entrent en collision? 9è jour de résidence du CLL: on en est là! (pour l'instant on se contente d'échange de couleur mais ça ouvre tellement de possibles narratifs!)

capture

Jour 12: Terminé un basique: un déplacement en essaims. Le rapport avec la bd numérique?... Imaginez qu'on attribue des comportements autonomes aux éléments qui constituent une bande dessinée: cases, bulles, personnages, décors... Je continue donc ma "collecte" de dispositifs-dont-je-ne-comprends-pas-que-personne-ne-s'en-soit-encore-inspiré-pour-faire-une-bd! Suite au prochain épisode... (Un soupçon de fierté: script entièrement conçu sans regarder aucun modèle ni emprunter de bouts de code, et pour moi, ça veut dire beaucoup!)

capture

Jour 14: Un document que vous ne lirez pas mais qui comporte une liste de 8 projets de dispositifs, en premier bilan des expérimentations des deux premières semaines.

bilan1-image

Jour 24: Mes "trucs & astuces"!

capture

Jour 30: Ce soir, LANCEZ-MOI DES DEFIS ! Proposez-moi des situations avec deux personnages qui peuvent être représentées avec une seule image. Les personnages peuvent être en interaction (ex : A discute avec B, A pète les dents de B...) ou non (ex : A et B admirent la mer). Evitez si possible de répéter une situation donnée par une personne avant vous : si quelqu'un a proposé « A offre un bouquet de fleurs à B », une proposition comme « B offre une truelle à A » fera doublon. Soyez fous!

strip-appel

Jour 31: Le compte-rendu du jour est déprimant. Ca fait deux semaines que j'ai fini de constituer ma « boîte à dispositifs » pour le projet « Les Entropiques », et depuis rien de rien, je tourne en rond, mon cerveau est vide, rien ne vient... J'ai pu profiter de ce temps pour bosser sur d'autres choses qui étaient mises de côté depuis longtemps ou totalement imprévues (un plug-in jquery perso, mes planches pour le prochain numéro de Gorgonzola, une interview, me plonger dans certaines oeuvres) et faire des rencontres stimulantes, mais en ce qui concerne le projet qui motive ma venue ici, RIEN. J'en viens à me demander si le modèle de la résidence est bien adapté à mon fonctionnement. Il est beaucoup trop erratique : les choses viennent quand elles ont décidé de venir, elles ne se soucient pas de savoir si elles ont des dates bien précises à respecter. Ou peut-être ce blocage vient-il du fait que je sois venu ici non pour travailler sur un projet déjà clairement défini mais pour en commencer un nouveau? Le plus énervant là-dedans, ce n'est pas cette situation, c'est ce qui risque d'arriver, comme à chaque fois : vendredi 25, à la veille de mon départ, des tas d'idées fuseront dans tous les sens dans mon cerveau alors que je n'aurais plus avant longtemps d'occasions comme celle-là de pouvoir m'y consacrer !

(Ce compte-rendu a été suivi d'un long échange sur Facebook, dont un des fils de discussion a réunit Philippe Marcelé, Thierry Smolderen, Lou Rhin, Joseph Béhé et moi-même. J'y mentionnais mes blocages du moment, et que je rencontre par ailleurs trop souvent: autant je m'amuse comme un petit fou à imaginer toutes sortes de dispositifs interactifs, autant je n'ai rien à mettre dedans, pas de contenu, pas d'histoire, ils tournent à vide, et c'est angoissant! Il a donc été question des risques auxquels on s'expose dans une pratique artistique dite de "laboratoire", qui vise à explorer tout le potentiel d'un médium de manière artificielle et en oubliant souvent de le rattacher au sensible...)

Jour 35: Imaginez une bande dessinée dont les cases comporteraient des zones transparentes et seraient (dés)empilables...

capture

Jour 39 : Mon cerveau, cette vaste blague. On lui donne 6 semaines pour bosser sur un projet, il se braque. Et puis 3 jours avant la fin, 2h30 du mat', un de ces déclics nocturnes dont il a le secret qui pourrait bien débloquer... un tout autre projet, coincé depuis l'été à sa trente-et-unième page.

Jour 40: Dernier jour. Bon bah... une image du tout autre projet alors, vu que j'ai intégralement remanié ses 31 premières pages depuis hier.

chant

Cette chronologie n'est pas exhaustive. Elle ne reprend pas l'intégralité des dispositifs testés ni les versions approfondies de certains de ceux présentés ici. De plus, elle ne rend compte que de ce qui est "montrable" à travers des images et pas de la réflexion. Le bilan reste malgré tout très mitigé car je n'ai pas su utiliser ce temps... Outre les raisons évoquées en jours 31 et 35, il faudrait en ajouter une plus personnelle: l'isolement à la campagne pour "trouver l'inspiration" n'était pas le bon format de résidence pour moi à cette période-là. Mais cela, je ne pouvais pas le prévoir au moment où j'ai accepté l'invitation du CLL il y a plusieurs mois! A défaut d'avoir "trouvé l'inspiration" pour Les Entropiques, j'ai quand même avancé sur des choses, connexes ou sans aucun lien (voir jours 31, 39 et 40). En ce qui concerne Les Entropiques, mon hypothèse de travail était beaucoup trop embryonnaire pour cette résidence. Même en forgeant des contraintes de création, celles-ci étaient encore trop vagues pour devenir "productrices", selon le terme consacré. Je rentre quand même avec une douzaine de nouveaux dispositifs interactifs auxquels je finirais bien par trouver une utilité (probablement de manière inattendue!) et le thème de l'entropie travaille toujours quelque part dans ma tête.

Résidence de création numérique

Je pars demain pour six semaines de résidence organisée par le Centre du Livre et de la Lecture Poitou-Charentes. Je reproduis ci-dessous la petite présentation faite sur le site:

Un nouvel auteur en résidence de création numérique

Anthony Rageul sera du 17 octobre au 26 novembre 2016, en résidence de création numérique BD.

Anthony Rageul, Tony de son nom d’auteur, résidera à côté de Poitiers pendant 6 semaines pour travailler à son nouveau projet BD numérique: Les entropiques. Chercheur, auteur de bande dessinée, il est spécialisé dans la BD numérique.

Il vit en Ille-et-Vilaine.

Il sera présent également pour des ateliers et des rencontres publiques pendant sa résidence.

« Le temps de la résidence ne sera pas celui de la finalisation ni de la réalisation complète d'une oeuvre, mais celui de la gestation et de l'écriture d'une oeuvre qui restera à réaliser. En menant une série d'expérimentations, je me fixe trois objectifs durant ce temps : écrire un scénario aussi abouti que possible, ébaucher un storyboard, fixer les choix de technologies. »

L'an dernier c'est Olivier Philipponneau qui a inauguré la résidence de création numérique organisée par le Centre du livre et de la lecture.

Bac+27324km

Depuis presque un an (et après dix ans d'études!), c'est le job de chauffeur-accompagnateur de personnes handicapées qui me permet de vivre. Alors youpi, j'ai bricolé quelques visualisations de mes circuits de septembre:

Les circuits de septembre 2016: 2484 kms.
Les circuits de septembre 2016: 2484 kms.
recadrage
Recadrage de l'image précédente. On reconnaît les voies et noeuds principaux, mais c'est désormais la fréquence de mes passages qui détermine leur importance.
Version gif animé.
Version gif animé.
Circuit le plus court du mois: 50 kms.
Circuit le plus court du mois: 50 kms.
Circuit le plus long du mois: 206 kms.
Circuit le plus long du mois: 206 kms.
Avec un peu de couleur...
Avec un peu de couleur...
Recadrage de l'image précédente.
Recadrage de l'image précédente.
Recadrage.
Recadrage.
Recadrage.
Recadrage.
Recadrage.
Recadrage.
Tri par kilométrage: magenta = 50-59 kms; bleu = 60-69 kms; cyan = 70-79 kms; vert = 80-89 kms; jaune = 90-99kms; rouge = 100-109 kms; blanc = >109kms.
Tri par kilométrage: magenta = 50-59 kms; bleu = 60-69 kms; cyan = 70-79 kms; vert = 80-89 kms; jaune = 90-99kms; rouge = 100-109 kms; blanc = >109kms.
Variantes d'un même circuit
Variantes d'un même circuit (selon usagers à desservir, conditions de circulation, etc.).
Recadrage de l'image précédente.
Recadrage de l'image précédente.
On peut s'amuser à obtenir des dessins abstraits en modifiant les paramètres des tracés (ici à partir de trois circuits). Les possibilités sont infinies.
On peut s'amuser à obtenir des dessins abstraits en modifiant les paramètres des tracés (ici à partir de trois circuits). Les possibilités sont infinies.
Pour finir, le fond de carte que j'ai utilisé, reconstitué à partir de Google Maps.
Pour finir, le fond de carte que j'ai utilisé, reconstitué à partir de Google Maps.

Les Monstres d’Amphitrite, making-of d’une bande dessinée numérique (8): quelques chiffres

Huitième et dernier billet du making-of des Monstres d'Amphitrite, avec quelques chiffres qui vont me mener à une ou deux réflexions rapides sur le financement du projet, autre aspect de la création.

250 : le nombre total de cases qui s'affichent successivement dans les quatre emplacements.

11 : le nombre de fichiers dont est constitué le site, sans inclure les images. Cela comprend les fichiers php, css et js (dont le plug-in jQuery animate-colors) et la police de caractère utilisée pour la barre de menu. On pourrait porter ce nombre à 12 en comptant le framework jQuery qui est implémenté depuis les serveurs de Google.

130 : nombre de lignes de code du script principal. Je suis un tout petit joueur. Il est réduit à 1930 caractères tenant sur une seule ligne dans la version minifiée utilisée en production. (Je ne comprends toujours pas comment ça marche !)

12 : heures par jour, pendant 3 semaines, c'est le temps qu'a pris la réalisation effective. La gestation et les essais ont en réalité commencé environ 6 mois plus tôt.

13 : nombre d'images créées par jour en moyenne, en tenant compte d'un jour de repos par semaine. C'est beaucoup : il est évident que cela serait difficile avec une technique de dessin plus traditionnelle (pas impossible toutefois avec un trait rapide). C'est de toutes façons trop de travail vis-à-vis du budget accordé à ce projet. En pleine « affaire » Pepper&Carrot (dont Xavier Guilbert et Julien Baudry livrent chacun une synthèse) et face à la paupérisation de la profession ou encore à la question récurrente des auteurs-débutants-prêts-à-tous-les-compromis-et-tirant-les-prix-vers-le-bas, je dois bien avouer que je ne me soucie pas assez du montant de mes rémunérations. D'abord parce que je suis incapable de me formater pour rentrer dans un budget donné d'avance, même si j'avais clairement posé au commanditaire un certain nombre de limites pour Les Monstres d'Amphitrite. D'autre part, parce que ce n'est pas ma source de revenu principale : je mène mes projets comme je l'entends, sans même chercher à ce qu'ils soient payés. Si quelqu'un est prêt à y mettre un peu d'argent, je ne dis pas non, et c'est tant mieux. Mais si j'attendais que l'on m'octroie des sommes correctes, soit je ne ferais jamais les projets qui me tiennent à cœur, soit j'en réduirais toujours les ambitions (au profit de la frustration) pour rentrer dans un budget donné... Deux perspectives aussi peu attrayantes l'une que l'autre...

4 : Le nombre de chiffres du montant de la rémunération, perçues en droits d'auteur. Dans un contexte d'absence de modèle économique qui fasse école pour la bande dessinée numérique, j'aimerais dire deux mots de la voie peu usitée que prend ce projet. Bien que je ne sois pas spécialiste de cette question, je crois pouvoir identifier aujourd'hui un certain nombre de source et modalités de revenus ou de financement pour la bande dessinée numérique : l'achat ou l'abonnement par le lecteur, les différentes formes de financements participatifs et de souscriptions par le public, et les différentes formes de mécénat et de production par différentes entreprises publiques ou privées de la presse et de l'audiovisuel. (Je n'inclus pas dans la liste l'édition traditionnelle, car c'est le papier qui y est rémunérateur, et pas directement le numérique.) Les Monstres d'Amphitrite entre dans un autre schéma : celui de la commande publique, plus proche de l'art contemporain, bien que le commanditaire (Mediatem) fasse partie des acteurs du livre. (Je dois préciser que le schéma originel était celui d'une résidence, avec un financement type bourse de création, mais la durée prévue ne me permettant pas de créer sur place, il s'est finalement bien plus apparenté à une commande.) Etrangement, je n'ai encore jamais bénéficié d'un circuit « normal », que ce soit celui de l'édition traditionnelle ou l'un de ceux listés ci-dessus pour la bande dessinée numérique. Ainsi, Ma Visite à la Maison de Santé relevait aussi de la commande publique. Le financement de la bande dessinée numérique peut donc aussi emprunter ces voies un peu moins habituelles que sont la bourse de création/résidence et la commande publique, dans le circuit de l'art contemporain. D'ailleurs, je vais bientôt en bénéficier de nouveau... A suivre...

Pour terminer, j'espère que ce making-of a pu être instructif. Je vous invite d'ailleurs à me faire part de vos retours, notamment de tous les auteurs et créateurs qui appréhendent l'aspect technique du numérique qui ont pu me lire et que j'espère avoir d'une certaine manière rassurés.

Les Monstres d’Amphitrite, making-of d’une bande dessinée numérique (7): Le retour du code!

Septième et avant-dernière partie de ce making-of et qui signe... le retour du blabla sur le code ! Il faut en effet oublier mes deux autres billets consacrés au code (billet 3 et billet 4)... Ou plutôt : il ne faut pas oublier les propos que j'y tiens mais le code que j'y présente car... ô douloureuse surprise, j'ai découvert en cours de réalisation du projet qu'il ne fonctionnait pas en conditions réelles ! C'est mon absence éhontée de logique qui m'a perdu dans les conditions de passage au chapitre ou à la case suivante. Bref, le seul code valide est celui que je présente aujourd'hui, tel qu'il est utilisé actuellement par le site.

Outre partager l'intégralité du script principal qui gère le fonctionnement des Monstres d'Amphitrite, je voudrais aussi poursuivre l'approche pédagogique des précédents billets. Après avoir retracé les opérations mentales de mise en place du code, j'aimerais continuer de développer ma réponse à la question « je comprends rien en informatique, comment ça marche tes trucs ? » Toujours à mon niveau de petit bricoleur, je tente ci-dessous d'expliquer ce que je comprends de ce qu'est un programme informatique à tous ceux qui n'en ont pas la moindre idée ! Vous me direz si le pari est relevé...

Petit mode d'emploi de ce billet : j'introduis plus ou moins longuement chaque partie de mon script, puis le script lui-même est truffé de commentaires (en orange) qui le détaillent ligne par ligne.

C'est parti !

L'objectif principal du programme est d'afficher la bonne case au bon moment au bon endroit au fil des clics du lecteur, et le faire changer de chapitre s'il y a lieu. Il va également déclencher divers événements annexes telles que le clignotement des contours de case. Pour assurer ces missions, le programme doit en permanence savoir « où on en est », c'est-à-dire quelle case est affichée à l'instant t, quelle sera la suivante, etc. A chaque clic du lecteur, ces paramètres évoluent. Pour le programme, ce sont des valeurs qui varient dans le temps de l'exécution : des variables. En premier lieu, on initialise les variables principales du programme : certaines se voient attribuer une valeur de départ qui changera au cours de l'utilisation, certaine se voient attribuer une valeur qui ne changera pas, enfin certaines sont encore vides et ne se verront attribuer de valeurs qu'ultérieurement au cours de l'utilisation. Pour les Monstres d'Amphitrite, nous avons besoin des variables suivantes :

var count = 0,//compteur de cases: indique le numéro de la case en cours à l'instant t
//
//tableau des listes de cases indiquant leur ordre d'activation et d'affichage 
successif pour chaque chapitre:
strList = [
   ['B A B A B A B A B C D'],
   ['B B A A A B D D B A B C A C D A B C D D D'],
   ['A A D B A B D C D B A A B D'],
   //choix multiple chapitre 3, une liste pour chacune des deux branches possibles:
   ['B B A C D B A D A D A D A D B D B D B D B D B D B B B B A B B A A A A B A B A 
   A A A A A A B B B A C D',
   'A A B B B D D D D C C C C A A A A B B B B B D D D D C C C C A A A A B B B B D 
    D D D C C C C A A A A B B B B D D D D C C C C A A A B B B D C'],
   //
   ['A A C C C D D D A C A D C D D B B D D A A C C C D C C C B A C C D'],
   ['A A A C A C A C A C A C B D B D B D B B B B D B D B D B D B D']
],
//
order = [],//servira le moment venu au stockage provisoire en mémoire de la liste 
de cases du chapitre en cours à l'instant t
img,//servira à stocker un objet image
choice = 0,//initialisation du nombre de choix de parcours possibles, par défaut zéro
timer;//sera utilisée pour les clignotements des cases
 

Le programme comporte ensuite un certain nombre de fonctions, c'est-à-dire plusieurs séries d'instructions qui vont être exécutées (ou « jouées », si on veut) à divers moments de la lecture, soit en fonction de la valeur de telle ou telle variable, soit en fonction d'une action du lecteur sur l'interface. Chaque fonction pourra être exécutée autant de fois que nécessaire durant l'utilisation.

Une première fonction va permettre d'adapter la taille des cases à la taille de la fenêtre du navigateur. Cette fonction va être déclenchée une fois au début de chaque chapitre, et également à chaque fois que le lecteur redimensionnera la fenêtre du navigateur. Rien de bien sorcier dans cette fonction : le programme récupère les dimensions de la fenêtre, puis il recalcule proportionnellement les dimensions des cases. Ce calcul se fait en deux temps et nécessite l'utilisation d'une condition : si la fenêtre est plus large que haute, les cases seront redimensionnées selon un premier calcul, si la fenêtre est plus haute que large, elles seront redimensionnées selon un second calcul. Comme les mots-clés des conditions sont en anglais dans ce langage (if...else), c'est plutôt facile à comprendre:

function redim() {
    //
    //récupération des dimensions de la fenêtre, moins les marges et menus:
    var largeur = $(window).width();
    var hauteur = $(window).height()-45-$('#footer').height();
    //
    //calculs des nouvelles dimensions des cases:
    if (largeur >= hauteur) {//si la fenêtre est plus large que haute
       var htrCase = hauteur*45/100;//nouvelle hauteur des cases = 45% de la hauteur 
       de la fenêtre
       if (htrCase>=400) {
          htrCase = 400;
       }//hauteur maximale des cases limitée à 400px
       var lrgCase = htrCase*500/400;//nouvelle largeur des cases proportionnelle à 
       la nouvelle hauteur
       $('.strip img')
       .css('height', htrCase)
       .css('width', lrgCase);//application des nouvelles dimensions à l'image
    } else {//ou (si la fenêtre est plus haute que large)
       var lrgCase = largeur*45/100;//nouvelle largeur des cases = 45% de la largeur 
       de la fenêtre
       if (lrgCase>=500) {
          lrgCase = 500;
       }//largeur maximale des cases limitées à 500px
       var htrCase = lrgCase*400/500;//nouvelle hauteur des cases proportionnelle à 
       la nouvelle largeur
       $('.strip img')
       .css('height', htrCase)
       .css('width', lrgCase);//application des nouvelles dimensions à l'image
    }
}
//
$(window).resize(redim);//exécution de la fonction redim() lors des redimensionnements 
de la fenêtre par l'utilisateur

La fonction qui suit n'est exécutée qu'une seule fois au début de chaque chapitre ; c'est pourquoi je l'ai appelée init(). Elle sert à assurer le bon affichage de la page et à définir certains paramètres propres au chapitre qui commence et que le programme a besoin de connaître (encore des variables !). Elle active enfin le clignotement de la première case cliquable et le préchargement de l'image suivante en exécutant ou appelant des fonctions que l'on va voir après.

function init() {
    //
    redim();//exécution de la fonction redim()
    //
    //définition du nombre de choix de parcours possibles pour les chapitres concernés:
    if (seq==2) {//note: la variable seq indiquant le numéro du chapitre en cours est 
    définie dans un autre fichier 
       choice = 2;
    }
    // 
    //récupération de la liste de cases correspondant au chapitre en cours 
    parmi les listes établies auparavant:
    order = strList[seq][folder].split(' ');//note: la variable folder indiquant le numéro
    du sous-dossier contenant les images est définie dans un autre fichier
    //
    $('#'+order[count])//définition de la case active...
    .css('cursor', 'pointer')//...des pointeurs de souris correspondants (la souris se 
    transforme en main quand on survole la case active)...
    .on('click', next);//...et appel de la fonction next() permettant le passage à la
    suite lors du clic
    preload(count+1);//préchargement de la case suivante
    //
    // clignotement de la case active:
    $('#'+order[count]).addClass('anim');//ajout d'un élément permettant au programme de 
    reconnaître quelle case est active et doit clignoter
    wink(100);//appel de la fonction wink(): le paramètre entre parenthèses indique 
    qu'elle sera jouée 100 fois 
    //
 }
 //
 init();//lancement du chapitre!

La fonction init() appelle notamment la fonction wink() qui assure le clignotement de la case actuellement cliquable. Il s'agit d'un changement de couleur progressif du contours qui est répété en boucle un certain nombre de fois afin de produire un effet de clignotement. Le nombre de fois que l'animation sera jouée est déterminée lors de l'appel à la fonction : j'ai choisi de la faire jouer 2 fois sauf pour la première case du chapitre ou en cas de choix multiples où elle est jouée 100 fois; afin de permettre au lecteur de se repérer en prendre ses marques, notamment quand la modalité d'interaction change soudainement de la convention fixée depuis le départ.

function wink(loop) {//le paramètre loop indique le nombre de fois que l'animation sera jouée
   //
   //définition d'une animation en boucle:
    //
    var j=0;
    //une fonction dans la fonction précise les instructions pour le clignotement:
    function anim() { 
       $('.anim')
       //la couleur du contours varie 4 fois de manière progressive sur une durée 
       de 100 millisecondes:
       .animate({borderColor:'#DDDDDD'}, 100)
       .animate({borderColor:'#000'}, 100)
       .animate({borderColor:'#DDDDDD'}, 100)
       .animate({borderColor:'#000'}, 100);
       j++;
       if (j<loop) { 
          timer = setTimeout(anim, 1000);//la fonction anim() est rejouée toutes les 
          secondes jusqu'à avoir été répétée le nombre de fois prévu
       }
    }
   anim();//la fonction anim() est déclenchée une première fois 
}

La fonction centrale sur laquelle tout repose est celle qui donne les instructions à suivre au moment où le lecteur clique sur une image. Faut-il afficher l'image suivante ou faut-il changer de chapitre ? Quelle image faut-il afficher à cet instant ou à quel chapitre faut-il passer ? Pour le déterminer, cette fonction vérifie les valeurs des variables qu'on a initialisées en début de programme, puis en actualise les valeurs après avoir effectué son travail. Ainsi, lors du clic, les variables changent de valeur et le programme saura toujours « où on en est » lors du clic qui suivra, etc. Une première série d'instructions fait en sorte de rendre « inactive » la case sur laquelle le lecteur vient de cliquer : logique puisque c'est la case suivante qui doit prendre le relais. Une seconde série d'instructions vérifie et assure les passage à la case ou au chapitre suivant et rend active la case qui doit le devenir.

function next() {
   //
    // "désactivation" de la case sur laquelle le lecteur vient de cliquer:
    $('.anim').removeClass();//retrait de l'élément permettant au programme d'identifier
    la case cliquée comme "active" 
    clearTimeout(timer);//arrêt du clignotement de la case cliquée
    $(this)
    .css('cursor', 'auto')//réinitialisation du pointeur de la souris sur la case cliquée
    .off('click', next);//désactivation du clic
    count++;//ajout de 1 au compteur de case 
    //
    //vérifications du remplissage des conditions requises pour passer à la case ou au 
    chapitre suivant et exécution des instructions en conséquence:
    //
    if (count>=order.length-choice) {//si le compteur de cases indique un numéro supérieur
    ou égal au nombre total de cases du chapitre...
       //
       //...alors exécution des instructions de fin de chapitre:
       seq++;//ajout de 1 au compteur de chapitres
       //
       if (choice>0) {//si le chapitre actuel se termine par un choix de parcours...
          //
          //...les x dernières cases affichées deviennent actives et clignotantes (x correspondant 
          au nombre de parcours possibles):
          for (j=0, i=count; i<=order.length; i++) {//pour toutes les cases concernées...
             $('#'+order[count]).addClass('anim');//...ajout d'un élément permettant au programme de 
             l'identifier comme "active"
             var a = '<a href="index.php?s='+seq+'&f='+j+'"/>';//...préparation d'un hyperlien vers
             la page correspondante...
             $('#'+order[count])
             .css('cursor', 'pointer')//...définition des pointeurs de souris...
             .wrap(a);//...et tranformation de la case en hyperlien
             count++;//ajout de 1 au compteur de cases
             if(j<choice) {
                j++;//répétition de ces instructions pour toutes les cases concernées
             } 
          }
          wink(100);//exécution de la fonction wink() pour 100 clignotements pour toutes les 
          cases concernées
          //
      } else {//sinon (= si le chapitre ne se finit pas par un choix de parcours)...
          //
          //...alors accès direct au chapitre suivant:
          location.href = 'index.php?s='+seq+'&f=0';
       }
       //
    } else {//sinon (= si le compteur de case n'indique pas un nombre supérieur ou égal au 
       nombre total de cases du chapitre)...
       //
       //...alors exécution des instructions d'affichage de la case suivante:
       //
       if (count>=order.length-choice-1 && seq>=strList.length-1) {//Si le compteur de cases 
          indique un nombre supérieur ou égal au nombre de cases du chapitre et si le compeur 
          de chapitres indique un nombre supérieur ou égal au nombre total de chapitres...
          //
          //...alors exécution des instructions de fin de l'histoire:
          $('#'+order[count]).attr('src', img.src);//affichage de la dernière image
          //
       } else {//...sinon...
          //
          //...affichage et activation de la case suivante: 
          $('#'+order[count]).addClass('anim');//ajout d'un élément permettant au programme 
          d'identifier la case comme "active"
          wink(2);//exécution de la fonction wink() pour 2 clignotements
          $('#'+order[count])
          .attr('src', img.src)//affichage de l'image suivante
          .css('cursor', 'pointer')//définition des pointeurs de souris
          .on('click', next);//appel à la fonction next() lors du clic sur la case active
          preload(count+1);//préchargement de l'image qui viendra après
       }
    }
 }

Il ne reste plus qu'une toute petite fonction : celle qui sert à précharger les images et qui a déjà été utilisée à plusieurs reprises :

function preload(i) {//le paramètre i indique le numéro de l'image à précharger
   img = new Image();//création d'un objet image
   img.src = 'images/SEQ'+seq+'/'+folder+'/'+i+'.png';//chargement de l'image dans l'objet image;
   le navigateur considère alors qu'il y a une image à charger dans le cache même si elle n'est
   pas immédiatement affichée à l'écran
 }

Si vous n'avez pas compris un traître mot de ce que je raconte, j'ai raté mon pari... Ne renoncez pas pour autant à la lecture du prochain billet: quelques remarques en guise de conclusion.