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.

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.

Les Monstres d’Amphitrite, making-of d’une bande dessinée numérique (6): Dessin

Sixième volet du making-of des Monstres d'Amphitrite avec un point sur le dessin, en deux temps : d'abord un retour rapide sur mon utilisation du pictogramme et ma pratique du dessin vectoriel, puis quelques points propres à ce projet.

La technique que j'emploie peut surprendre: je dessine en me passant totalement de la « gestuelle » traditionnelle du dessin, qu'elle soit celle du crayon sur le papier ou du stylet sur la tablette. J'utilise uniquement la souris, non pour tracer quoi que ce soit, mais, du bout du pointeur saisir, déplacer et modifier des tracés point par point. Mes personnages sont en réalité des squelettes, exactement comme on peut se figurer des squelettes de personnage en 3D, sauf qu'ils sont en 2D.

Course de squelettes...
Course de squelettes...

Au fil du temps et des bandes dessinées réalisées, j'ai tant accumulé de squelettes dans toutes les positions et d'objets et éléments de décor divers que je n'ai plus qu'à piocher dans cette réserve et à copier-coller à tout-va ! Quand cela est nécessaire, je crée de nouveaux pictogrammes. D'ailleurs, pour Les Monstres d'Amphitrite, il y a une quantité non négligeable de pictogrammes inédits !

Pictogrammes inédits réalisés pour Les Monstres d'Amphitrite.
Pictogrammes inédits réalisés pour ce projet.

Voilà pour ce qui était des généralités. Les Monstres d'Amphitrite voit apparaître certaines particularités de traitement. La première est évidemment le fait que la planche est en évolution permanente : tout le jeu de juxtaposition des cases ne se joue plus seulement dans l'espace de la page, mais aussi dans le temps de la lecture. Dans le billet précédent, on voit comment je procède pour le storyboard par empilement de post-it. Je fais un peu la même chose dans mes fichiers images. En réalité, un seul fichier par chapitre contient toutes les cases et combinaisons possibles du chapitre en question. Chaque case est dessinée sur un calque distinct (empilement). Je travaille la composition sur l'ensemble de la planche grâce à l'utilisation de quatre plans de travail, correspondant aux quatre emplacements prévus pour les cases (juxtaposition). L'outil « plans de travail » disponible dans cette version du logiciel a également un autre avantage considérable : chacun de ces plans de travail peut être exporté séparément. Je peux donc composer l'image sur l'ensemble de la planche et dessiner des formes chevauchant les cases tout en exportant séparément chacune des cases.

Deux exemples d'utilisation des calques (empilement) et des plans de travail (juxtaposition).
Deux exemples d'utilisation des calques (empilement) et des plans de travail (juxtaposition).

Deuxième particularité, l'usage de trames. C'est quelque chose qui est apparu il y a un peu plus d'un an dans mes bandes dessinées papier : je voulais redonner de la matière, de la texture à mes dessins, tout en conservant un côté mécanique. Quelque chose qui soit « crade », mais néanmoins machinique. Dans les Monstres d'Amphitrite, j'avais aussi besoin de masses dont je puisse me servir pour équilibrer la composition, dans la mesure où de nombreux déséquilibres apparaissaient dans les cases puisque je composais au niveau de la planche. Enfin, l'usage des trames permet de produire des effets « expressifs ».

Usage des trames.
Usage des trames.

Troisième et dernière particularité, l'inclusion d'éléments dessinés à la main. Cela fait maintenant un certain temps que j'introduis ici ou là des éléments dessinés à la main dans mes bandes dessinées. Ici, j'ai restreint cette utilisation aux emanatas et à la typographie. Cela rompt le côté mécanique pour un résultat plus expressif. Cela a été plutôt difficile à gérer puisque je ne me rappelais plus du tout de la manière dont j'avais réussi à résoudre le problème des effets d'aliasing dans un précédent projet. Du coup, je n'ai jamais pu trouver une façon de faire durable et j'ai changé pour chaque chapitre, avec un résultat assez aléatoire, qui ne me satisfait pas beaucoup...

Montage de quelques scans d'éléments dessinés à la main avec des crayons sur du papier.
Montage de quelques scans d'éléments dessinés à la main avec des crayons sur du papier.

Voilà en ce qui concernait le dessin. Les deux prochains billets vont clore ce making-of.

Les Monstres d’Amphitrite, making-of d’une bande dessinée numérique (5): Ecriture et storyboard

Après une longue interruption, voici enfin la suite du making-of des Monstres d'Amphitrite. Il me sera d'ailleurs plus facile d'en parler maintenant que le projet est sorti (si vous ne l'avez pas encore vu, c'est là!) sans craindre de trop en dévoiler. Dans ce billet, il sera question de l'écriture et du storyboard et, au-delà de ça, des différents phases que je traverse lors de la gestation d'un projet de ce type.

D'abord, il est important pour comprendre la suite de dire que la gestation du projet a démarré quelques mois en amont : dès l'automne 2015, j'ai testé des outils, en particulier la librairie jCanvas, excellent outil que j'ai finalement abandonné mais auquel je reviendrai très certainement. Et dès l'automne, j'ai commencé à réfléchir au projet, tranquillement, sans rien poser sur le papier. Durant cette phase, un problème a émergé peu à peu...

Avant de commencer, il faut aussi rappeler que j'ai prédéterminé en amont une interface bien particulière, que j'ai présenté dans le deuxième billet de ce making-of. En ce qui concerne les raisons de ce choix (improvisation, gestion du temps, parcours multiples possibles), je renvoie au même billet. Au final, je me trouve confronté à une contrainte forte : l'histoire, quelle qu'elle soit, devra s'inscrire dans ce dispositif particulier que j'appelle « planche évolutive ».

L'idée était de me laisser aller à l'improvisation à l'intérieur de ce cadre. Une première phase a donc consisté, sans véritablement savoir où j'allais, à storyboarder directement des séquences, encore non reliées entre elles. C'est une mise en scène très directe, très rapide, à grands coups de crayon, d'intuitions diverses. En voici quatre exemples au format gif animés :

Recherche pour une séquence introductive.
Recherche pour une séquence introductive.
Autre recherche pour une séquence introductive.
Recherche pour une séquence introductive.
Recherche pour l'apparition des monstres.
Recherche pour l'apparition des monstres.
Recherche pour l'apparition des monstres.
Recherche pour l'apparition des monstres. Ces deux derniers exemples préfigurent déjà largement la version définitive, avec cette lecture circulaire.

Dès les tous premiers instants de cette phase de recherche, le problème qui me travaillait dès le début de ma réflexion quelques mois plus tôt s'est fait plus insistant. Initialement, le projet devait consister en une adaptation de la légende du Lion de Terre et du Lion de Mer, qui donne une origine mythologique aux deux îlots du même nom au large de Saint Raphaël. Mais face à mon rapport douloureux à l'actualité et face à une déconfiture dans ma vie personnelle, cette idée me paraissait de plus en plus vaine : j'avais autre chose à raconter qu'une énième fiction. Dès lors, pour la première fois, le projet allait devenir en partie autobiographique, tout en conservant la trame originelle de la légende. J'avais envie de savoir, expérimentalement, ce qui allait se produire quand les événements précités entreraient en collision avec le scénario antique. C'est à partir de cette décision radicale que le projet démarre vraiment.

Parallèlement aux premiers storyboards, je peaufinais le code et faisais plusieurs bouts d'essai (je renvoie à nouveau au billet n°2 pour un exemple au format gif animé). Ce qui ressortait de toutes ces recherches ne me convenait pas mais je ne savais pas encore pourquoi. C'est là qu'intervient ce que j'appelle l'inspiration ou je ne sais quel genre de déclics. En l'occurrence, il en a fallu trois. Le premier concerne la forme : cette grille de 3x3 cases me posait problème. Elle complexifiait beaucoup l'écriture alors que j'avais peu de temps, et elle rendait la mise en forme du propos très mécanique. Le déclic soudain a consisté à resserrer à une grille de 2x2 cases : outre le gain d'efficacité, j'ai pu entrer pleinement dans des jeux visuels beaucoup plus poétiques. Le second déclic découle directement du premier : j'ai accepté douloureusemment de renoncer à « superposer » l'histoire à une carte du golfe de Fréjus, levant ainsi une énorme contrainte formelle. A noter que je m'étais fixé cette contrainte pour jouer avec la légende, qui explique que la naissance des deux îlots est due à Poséidon, qui aurait figé là les deux monstres. Le troisième déclic concerne l'histoire : tous les premiers jets disparates et les diverses idées restant encore à l'état de vue de l'esprit se sont soudainement assemblées de manière claire :

Un déclic en plein sommeil: au milieu de la nuit, je jette en quelques secondes sur le papier le fil rouge de toute l'histoire.
Un déclic en pleine nuit: je me réveille en sursaut, jette en quelques secondes sur le papier le fil rouge de toute l'histoire et retourne me coucher.

A partir de là, tout ne coule pas de source, mais le projet prend un rythme beaucoup plus soutenu. Je commence la réalisation des premières séquences dans leur forme définitive tout en continuant parallèlement le storyboard des séquences suivantes. Je bosse environ 12 heures par jour et boucle tout le projet en un peu moins de trois semaines (alors que la phase de gestation et les premières recherches décrites ci-dessus se font par micro-bonds disséminés sur environ six mois). J'inaugure un nouvel outil pour le storyboard : rien de tel que des post-it pour improviser librement ! Ils me permettent de jouer avec les jeux visuels et l'agencement des cases tout en facilitant grandement les repentirs.

L'ensemble du storyboard tient dans sept petits paquets de post-it.
L'ensemble du storyboard tient dans sept petits paquets de post-it. Ci-dessous, storyboard intégral en vidéo:

Je crois que les images sont assez claires. Les changements de couleurs de post-it trahissent les innombrables repentirs. Les post-it fluos sont issus de versions anciennes de certaines séquences et ont été recyclés dans les séquences définitives (c'est particulièrement net dans le passage du monstre blanc). C'est ce que je voulais dire quand je disais que tout ne coulait pas de source : je n'ai pas pu compter le nombre de versions de chaque séquence tant il y en a eu. Pour preuve :

Les chutes : toutes ces cases ont un jour fait partie d'une version des Monstres d'Amphitrite puis en ont finalement été exclues.
Les chutes : toutes ces cases ont un jour fait partie d'une version des Monstres d'Amphitrite puis en ont finalement été exclues.

Voilà tout pour ce billet. La prochaine fois, on parlera de dessin vectoriel !

 

Lecture commentée des Monstres d’Amphitrite

En attendant la suite du making-of, une nouvelle vidéo vient d'être postée sur la page de documentation autour des Monstres d'Amphitrite. Il s'agit d'une "lecture commentée", un peu à la manière des commentaires audio de réalisateurs sur les DVD. Vous pouvez donc la retrouver sur la page en question, mais je la poste également ci-dessous. (Je dois avouer ne pas avoir regardé le montage final.)

Les monstres d’Amphitrite, making-of d’une bande dessinée numérique (4): Codage de l’interface (2/2)

Quatrième billet de ce making-of et deuxième et dernière partie consacrée à la programmation de l'interface.

Pour rappel, je tente ici de répondre le plus simplement possible à une question que l'on m'a souvent posée : « comment ça marche tes trucs ? » et, collatéralement, « qu'est-ce que c'est, la programmation ? » Dans le dernier billet, j'ai répondu en disant : « c'est donner des ordres, des instructions à l'ordinateur ». Permettez-moi aujourd'hui de compléter : c'est donner des instructions à un ordinateur dans sa langue. Prenons un tout petit extrait du code utilisé dans Les Monstres d'Amphitrite :

billet04-1

Dans ce bout de code, je m'adresse directement à l'ordinateur pour lui demander certaines choses. Je le fais dans sa langue (ou plutôt l'une de ses langues : il en connait plusieurs). C'est exactement la même chose que parler une autre langue, que parler anglais ou espagnol. Je peux même m'amuser à traduire ce bout de code en français, ligne par ligne, phrase par phrase. Ca dit : « s'il-te-plaît adorable ordinateur, peux-tu faire en sorte que lorsque je passe la souris sur la case n°x (1), le pointeur de la souris prenne la forme d'une main-au-doigt-pointant (2); et que lorsque je clique dessus, cela déclenche les opérations permettant de passer à la case suivante (3)? » La langue utilisée ici est Javascript, dans une forme simplifiée grâce au framework jQuery. Hé bien on peut filer la métaphore de la langue encore plus loin. La différence entre Javascript et jQuery est analogue à la différence qui existe entre les différents niveaux de langage. Javascript est littéralement le niveau châtié de la langue, et jQuery le niveau courant ou familier : formes et tournures abrégées, grammaire et syntaxe simplifiées.

Quand je rédige un script, je fais un vrai exercice de traduction, du français (langue dans laquelle je rédige, au brouillon, les séries d'instructions indivisibles dont je parlais dans le précédent billet) vers le Javascript. La traduction est possible dans les deux sens. (Toute cette réflexion a fait l'objet de la performance Cache-cache, en 2013, dont vous pouvez voir la vidéo en ligne).

Revenons-en au script et en particulier aux « fioritures » de l'interface. Et ça commence par une erreur de conception majeure. La partie principale du script, celle qui fait avancer l'histoire, était destinée à être la plus souple possible. Je voulais qu'elle puisse fonctionner quel que soit le nombre de case, quelless que soient leur position et leurs dimensions, de manière à ce que cela puisse resservir pour d'autres histoires, mais aussi pour d'autres personnes (servez-vous ! Vous pouvez utiliser librement ce code!). Je voulais également me réserver la possibilité de créer des parcours à choix multiples à l'intérieur de mon récit. Hé bien ça, j'aurais dû y penser en amont, dès le départ, car la logique de mon script s'est avérée totalement incompatible avec les parcours multiples. N'ayant eu aucune envie de tout reprendre à zéro, j'ai bricolé un truc qui fonctionne pour Les Monstres d'Amphitrite, mais qui n'a aucune souplesse. Le script qui suit est donc prévu pour un unique cas : en fin de chapitre, un certain nombre de choix de parcours peuvent être proposés (le maximum possible étant défini par le nombre de cases à l'écran); mais chaque parcours ne dure que le temps d'un chapitre, tous les parcours se rejoignent au chapitre suivant et il faut repasser par ce nœud commun avant de proposer à nouveau plusieurs choix. Comme vous le voyez, c'est vraiment pour un cas de figure unique...

billet04-2

Ce bricolage a d'abord nécessité de revoir toute la hiérarchie du stockage des images en créant, dans chaque dossier d'images (un par chapitre, nommés ci-dessus « SEQ0 », « SEQ1 », etc.), un sous-dossier pour chaque branche possible dans le chapitre concerné (nommés « 0 », « 1  », « 2 », etc.).

billet04-3

Lors de l'initialisation, on indique quels chapitres offrent plusieurs choix à la fin de leur lecture, et combien de choix ils offrent (1). Par exemple dans cette version, on a 3 choix à la fin du chapitre 1. (Pour paramétrer plusieurs chapitres, on aurait pu utiliser une structure switch...case à la place de la structure if.) Ce sont les x derniers emplacements de la liste qui seront cliquables simultanément. Par exemple ici, pour 3 choix de parcours en fin de chapitre 1, ce sont les emplacements B2, C2, et A3 qui seront cliquables et clignoteront de manière simultanée (2).

billet04-4

Dans le dernier billet, on avait vu ce qui se passait au moment du clic dans le cas où il n'y avait pas de changement de chapitre et dans le cas où il y avait un changement de chapitre sans choix de parcours. On avait laissé de côté le dernier cas de figure : ce qui se passe lors du clic si on est arrivé à la fin d'un chapitre (1) qui offre plusieurs choix de parcours (2). Dans ce cas :
(3) On indique que l'on change de chapitre.
(4) Pour chaque choix de parcours, on applique à chaque emplacement correspondant le traitement suivant :
(5) On définit un lien vers le bon chapitre.
(6) On transforme l'emplacement correspondant en lien tel que défini en (5) et on le rend cliquable.
(7) Ce compteur permet d'interrompre la procédure une fois que tous les emplacements nécessaires ont été traités.
(8) et (9) On fait clignoter les emplacements.

Il reste deux fioritures à voir. Je les commenterai rapidement mais sans les détailler cette fois. D'abord, une partie du script permet de redimensionner l'ensemble des images de manière à s'adapter à la taille du navigateur de chaque utilisateur :

billet04-5

Ce sont de simples calculs de proportionnalité (vous savez, le tableau en croix ou règle de trois). Remarquez que je rentre en « dur » les dimensions des images dans le code, car je les connais d'avance et qu'elles font toutes la même taille (là encore, ça ne vaut donc que pour ce projet-là). Cela évite de devoir demander au programme de détecter automatiquement les dimensions des images, avec les problèmes que ça ne manque jamais de poser en terme de détection de la fin du chargement de chaque image.

Enfin, pour finir, voici la fonction qui fait clignoter le contours des emplacements quand ils sont cliquables :

billet04-6

C'est une simple animation qui se répète en boucle un certain nombre de fois (En l'état actuel du projet, 100 fois au début du premier chapitre et quand il y a choix de parcours, 2 fois dans les autres cas).

Les monstres d’Amphitrite, making-of d’une bande dessinée numérique (3): Codage de l’interface (1/2)

Troisième billet de ce making-of : la création de l'interface . Autrement dit, je vais vous ouvrir le capot et vous montrer le moteur : le script principal de l'interface, celui qui rend la bande dessinée interactive. Deux billets ne seront pas de trop pour ce faire : celui-ci est consacré au cœur du dispositif, et le prochain sera consacré aux fioritures.

Evidemment, je vais parler programmation. Comme je ne voudrais pas vous dégoûter de suivre ce making-of dès le troisième billet, sachez qu'après ces deux-là consacrés à la programmation, je reviendrai à des aspects plus « conventionnels » : storyboard, dessin... Je vais parler programmation donc, mais je ne vais pas être trop technique. D'abord parce que je suis médiocre en ce domaine, petit bidouilleur dont les bricolages feront rire les développeurs avertis. Ensuite, et surtout, plus que détailler le code, je souhaite donner un aperçu de la logique qui peut présider à ce genre de création numérique, le processus qui mène des idées à la réalisation concrète. Bref, j'aimerais essayer d'apporter un début de réponse à celles et ceux qui ont pu me demander : « je comprends rien en informatique, comment ça marche tes trucs ? »

Avant d'entrer dans le script principal, deux mots sur la « mise en page ». C'est une seule et même page html qui affiche successivement chaque chapitre. Cette page est générée en php et utilise des paramètres passés dans l'url.

Vous n'avez rien compris ? Je reprends : le site ne comporte qu'une seule page. A chaque changement de chapitre, cette page est rechargée avec des contenus, images et caractéristiques différentes. Pour ce faire, je lui donne des consignes dans un autre langage (php), grâce auxquelles elle va aller chercher les bonnes images, au bon endroit et au bon moment.

Le script principal quant à lui est rédigé en langage Javascript, avec l'aide de jQuery. Aujourd'hui, on va s'intéresser exclusivement au cœur du programme, à savoir à la partie du script qui permet d'avancer de case en case et de chapitre en chapitre. La première étape consiste à définir ce que l'on veut obtenir exactement. En l'occurrence, on veut qu'au moment où le lecteur clique sur une case, le système affiche la case suivante au bon emplacement ou lance le chapitre suivant si on est arrivé en fin de chapitre. Remis dans le bon ordre, cela donne :

Lors du clic sur une case, le système doit :
1. Déterminer si on est arrivé en fin de chapitre.
2. Si oui : on change de chapitre.
3. Si non : on affiche la case suivante au bon emplacement.
Facile !

Toute la logique ensuite va consister à détailler ces réactions que l'on veut obtenir de l'interface en un nombre fini d'instructions indivisibles (comme une recette de cuisine). Je ne sais pas si les développeurs ont une méthode particulière, la mienne consiste en un élagage progressif. Je décompose chaque étape en une série de sous-étapes, puis je décompose chacune des sous-étapes obtenues en une nouvelle série de sous-étapes, et ainsi de suite, jusqu'à ne plus pouvoir subdiviser. Par exemple, pour afficher la case suivante au bon emplacement :

Lors du clic, déclenchement successif des actions suivantes :
1. Rendre non-cliquable la case sur laquelle on vient de cliquer.
2. Déterminer quel est le prochain emplacement.
3. Y afficher la case.
4. La rendre cliquable à son tour.

Puis on continue en subdivisant chacune de ces étapes en sous-étapes, et ainsi de suite, jusqu'à obtenir une succession d'instructions indivisibles. Par exemple, pour l'étape 2 ci-dessus, il faut :
1. Obtenir le numéro de la case à venir.
2. Aller dans la liste des emplacements du chapitre actuel et chercher l'item dont la position dans la liste correspond au numéro de la case à venir.
3. Afficher la prochaine image (qui a été préchargée en amont) dans l'emplacement désigné par l'item récupéré à l'étape 2.
L'utilisation de jQuery permet de réduire le nombre d'instructions : par exemple, l'étape 3 ci-dessus est indivisible avec jQuery, alors qu'elle nécessite une autre série de sous-étapes en Javascript pur.

Bref, vous savez maintenant ce que signifie « programmer » : décomposer l'ensemble des actions voulues en une séries d'instructions indivisibles et correctement ordonnées. Ce sont ces instructions que notre interface va suivre pour répondre correctement aux actions du lecteur. On peut maintenant jeter un œil à la partie principale du script (sans entrer dans les détails et subtilités) :

billet3-1

On va d'abord avoir besoin d'entrer certaines données dans le programme :
(1) Un compteur, permettant de compter les cases successives.
(2) Des listes définissant la succession des emplacements telles que déterminées par le storyboard. Il y a une liste par chapitre. Dans le fichier html, chaque emplacement porte un identifiant unique : ce sont ces identifiants que l'on utilise ici. Dans cette version, je les ai identifiés selon un quadrillage, comme à la bataille navale : A1, B1, C1 … A3, B3, C3. (Bien sûr, cette nomenclature est possible parce que la planche affichée est un gaufrier régulier. Il ne faudrait pas oublier que tout cela, c'est de la bande dessinée avant tout!)
(3) Par exemple, dans le troisième chapitre (3è liste), ce sont successivement les emplacements C1, puis A1, puis à nouveau A1, puis A2, etc. qui accueilleront une nouvelle case et deviendront cliquables.
Pour les connaisseurs de Javascript : j'aurais pu rédiger chaque liste sous forme de tableau mais ça aurait été une plaie en virgules et en guillemets, alors j'ai préféré des chaînes de caractères. Un peu plus loin dans le code, j'applique la méthode split() aux chaînes.

Continuons : il faut d'abord assurer le premier chargement de la page : c'est le rôle de la fonction init(). :

billet3-2

Au premier chargement de la page...
(1) ...on redimensionne toute l'interface en fonction de la taille de la fenêtre du navigateur de l'utilisateur.
(2) ...on rend cliquable le premier emplacement qui doit l'être.
(3) ...on précharge la prochaine case à être affichée.
(4) ...on a ici une première fioriture: on fait clignoter le contours du premier emplacement pour indiquer au lecteur qu'il est cliquable.
(5) ...on a ici une seconde fioriture que je détaillerai la prochaine fois, mais que je dois signaler pour comprendre la suite : on indique si tel ou tel chapitre se termine en proposant plusieurs choix de parcours au lecteur.

Et enfin, on arrive dans le cœur du dispositif, avec la fonction qui permet d'avancer, de case en case et de chapitre en chapitre:

billet3-3

Lorsque l'utilisateur clique sur la case qui clignote :
(1) ...on stoppe le clignotement.
(2) ...on rend non-cliquable la case qui vient d'être cliquée.
(3) ...si on est arrivé à la fin du dernier chapitre, il ne se passe plus rien à partir de là (la suite du code ne sera pas « jouée »).
(4) ...on indique que l'on passe à la case suivante.
(5) ...si on est arrivé à la fin du chapitre...
(6) ...et qu'il n'y a pas de parcours multiples...
(7) ...on passe au chapitre suivant.
(5) ...si on n' est pas arrivé à la fin du chapitre...
(8) ...on va poursuivre l'affichage successif des cases, comme suit :
(9) …on fait clignoter l'emplacement suivant,
(10) ...on y affiche l'image prévue qui a été préalablement préchargée,
(11) ...on le rend cliquable,
(12) ...et enfin on précharge l'image qui vient après.

Voilà tout pour aujourd'hui ! N'hésitez pas à me faire des retours sur ce making-of, c'est une expérience que tout cela ! Et surtout, dites-moi si cela était assez clair (ou pas) pour des novices ? Merci !