Re: ANIM ORAVOX

Post a reply

Confirmation code
Enter the code exactly as it appears. All letters are case insensitive.
Smilies
:D :) ;) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :!: :?: :idea: :arrow: :| :mrgreen: :geek: :ugeek:

BBCode is ON
[img] is ON
[flash] is ON
[url] is ON
Smilies are ON

Topic review
   

If you wish to attach one or more files enter the details below.

Expand view Topic review: Re: ANIM ORAVOX

Re: ANIM ORAVOX

by JYS » Wed Oct 01, 2025 9:34 am

Ok! Bien installé le bodymovin plugin.
Je vais voir comment cela fonctionne et je vous tiens au courant!

Re: ANIM ORAVOX

by Marcel » Tue Sep 30, 2025 1:00 pm

JYS wrote: Thu Sep 25, 2025 7:42 pm Sergre, tes petites anims postées ci dessus, tu peux les transformer en Lottie, sans problèmes.
Dixit AI : "- a Lottie file can be derived from an animated PNG (APNG) or, more accurately, from an image sequence"
Whopah! ;)

LottieFiles: The LottieFiles platform is a go-to resource for all things Lottie. While they have an "Images to Lottie" converter, it's a very simple tool that takes individual PNGs/JPGs and creates a basic Lottie file that plays them in sequence. This is the most direct way to achieve what you're asking for, but the resulting Lottie file will be larger and not scalable like a true vector Lottie.

Lottielab: This is an online editor for Lottie animations. You can import images and then use their tools to animate them. While it's not a direct converter, you could import your APNG as a series of individual frames and then create the Lottie animation from those.

SVGator: This is an online animation tool that can export to various formats, including Lottie. You can import vector graphics (like SVG) and raster images (like PNGs) and then animate them. It is more of an animation creation tool than a simple converter, so it gives you more control over the final product.

loading.io: This site has a feature where you can upload images to create an animation. It supports various formats, and in some cases, can create a Lottie animation that embeds your raster images.

Ah les miracles de l'AI!

Sergre, tes petites animations postées ci-dessus, tu peux les transformer en Lottie, sans problème.
Dixit AI : « - un fichier Lottie peut être dérivé d'un PNG animé (APNG) ou, plus précisément, d'une séquence d'images. »
Whopah ! ;)

LottieFiles : La plateforme LottieFiles est une ressource incontournable pour tout ce qui concerne Lottie. Bien qu'elle propose un convertisseur « Images vers Lottie », il s'agit d'un outil très simple qui prend des PNG/JPG individuels et crée un fichier Lottie basique qui les lit en séquence. C'est la méthode la plus directe pour obtenir ce que vous souhaitez, mais le fichier Lottie résultant sera plus volumineux et ne sera pas redimensionnable comme une vraie Lottie vectorielle.

Lottielab : Il s'agit d'un éditeur en ligne pour les animations Lottie. Vous pouvez importer des images et utiliser leurs outils pour les animer. Bien qu'il ne s'agisse pas d'un convertisseur direct, vous pouvez importer votre APNG sous forme d'une série d'images individuelles, puis créer l'animation Lottie à partir de celles-ci.

SVGator : Il s'agit d'un outil d'animation en ligne permettant d'exporter vers différents formats, dont Lottie. Vous pouvez importer des images vectorielles (comme SVG) et des images matricielles (comme PNG), puis les animer. Il s'agit davantage d'un outil de création d'animations que d'un simple convertisseur, ce qui vous offre un meilleur contrôle sur le résultat final.

loading.io : Ce site propose une fonctionnalité permettant de télécharger des images pour créer une animation. Il prend en charge différents formats et, dans certains cas, peut créer une animation Lottie intégrant vos images matricielles.

Ah les miracles de l'IA !
Bonjour Jean-Yves,

Il est possible de creer directement les animations lotties dans After Effect.
Tu dois telecharger un plugin et une fois installé plus besoin d'internet.
Voici le lien vers le plugin: https://github.com/airbnb/lottie-web/ra ... ymovin.zxp
( Et un programme pour installer les plugin AE: https://updates.aescripts.com/win/aescr ... tup%29.exe).

Re: ANIM ORAVOX

by SergeV » Sat Sep 27, 2025 12:48 pm

BONJOUR JEAN YVES
Pourrais tu voir dans mon fichier Corel plus haut,
pourquoi je ne peux pas faire de svg ???
j'ai encore un problème couleur et je ne sais pas comment faire pour modifier
et toi tu peux les faires ? a partir de cela?


merci.
Serge

Re: ANIM ORAVOX

by SergeV » Fri Sep 26, 2025 2:03 pm

Merci Jean Yves, je vais essayer avec les animes PNG pour voir le poids que ca prend
REMARQUE ;
Les animes pnga ne vont pas changer de format vers une taille plus grande... ! La taille seras la même sur n'importe quel écran.
donc pas de pertes en qualité. Non?

Re: ANIM ORAVOX

by JYS » Thu Sep 25, 2025 7:42 pm

Sergre, tes petites anims postées ci dessus, tu peux les transformer en Lottie, sans problèmes.
Dixit AI : "- a Lottie file can be derived from an animated PNG (APNG) or, more accurately, from an image sequence"
Whopah! ;)

LottieFiles: The LottieFiles platform is a go-to resource for all things Lottie. While they have an "Images to Lottie" converter, it's a very simple tool that takes individual PNGs/JPGs and creates a basic Lottie file that plays them in sequence. This is the most direct way to achieve what you're asking for, but the resulting Lottie file will be larger and not scalable like a true vector Lottie.

Lottielab: This is an online editor for Lottie animations. You can import images and then use their tools to animate them. While it's not a direct converter, you could import your APNG as a series of individual frames and then create the Lottie animation from those.

SVGator: This is an online animation tool that can export to various formats, including Lottie. You can import vector graphics (like SVG) and raster images (like PNGs) and then animate them. It is more of an animation creation tool than a simple converter, so it gives you more control over the final product.

loading.io: This site has a feature where you can upload images to create an animation. It supports various formats, and in some cases, can create a Lottie animation that embeds your raster images.

Ah les miracles de l'AI!

Sergre, tes petites animations postées ci-dessus, tu peux les transformer en Lottie, sans problème.
Dixit AI : « - un fichier Lottie peut être dérivé d'un PNG animé (APNG) ou, plus précisément, d'une séquence d'images. »
Whopah ! ;)

LottieFiles : La plateforme LottieFiles est une ressource incontournable pour tout ce qui concerne Lottie. Bien qu'elle propose un convertisseur « Images vers Lottie », il s'agit d'un outil très simple qui prend des PNG/JPG individuels et crée un fichier Lottie basique qui les lit en séquence. C'est la méthode la plus directe pour obtenir ce que vous souhaitez, mais le fichier Lottie résultant sera plus volumineux et ne sera pas redimensionnable comme une vraie Lottie vectorielle.

Lottielab : Il s'agit d'un éditeur en ligne pour les animations Lottie. Vous pouvez importer des images et utiliser leurs outils pour les animer. Bien qu'il ne s'agisse pas d'un convertisseur direct, vous pouvez importer votre APNG sous forme d'une série d'images individuelles, puis créer l'animation Lottie à partir de celles-ci.

SVGator : Il s'agit d'un outil d'animation en ligne permettant d'exporter vers différents formats, dont Lottie. Vous pouvez importer des images vectorielles (comme SVG) et des images matricielles (comme PNG), puis les animer. Il s'agit davantage d'un outil de création d'animations que d'un simple convertisseur, ce qui vous offre un meilleur contrôle sur le résultat final.

loading.io : Ce site propose une fonctionnalité permettant de télécharger des images pour créer une animation. Il prend en charge différents formats et, dans certains cas, peut créer une animation Lottie intégrant vos images matricielles.

Ah les miracles de l'IA !

Re: FICHIER COREL DE TRAVAIL serge

by SergeV » Thu Sep 25, 2025 12:07 am

fichier COEL POUR ANIMES VECTORIEL.
serge
Attachments
A_ANIM-ORAVOX-COREL-serge.zip
(11.31 MiB) Downloaded 3 times

TOPO DES ANIMES

by SergeV » Tue Sep 23, 2025 10:51 am

OK Marcel et jean Yves donc :
Tres bonne idée, tu en penses quoi JY c'est faisable pour toi?

il y a 6 animes en tout qui défilent selon un timing.

1) la cloche : Apparition du talisman sans enregistrement. 3sec
2) juste apres la cloche vient l'enregistrement choix de 4 sec avec une anime spécifique "minuteur"
3) Le médaillon central du talisman. le petit chat apparait, qui regarde de gauche a droite, et qui symbolise la sélection manuel, si rien est pris en compte en vocal. Temps d'action manuelle 1h ; et si aucune sélection manuelle est faite endéans l'heure, déconnexion.?
4) la transition sur l'écran vers la pages synopsis une anime ou simplement un fondus d'images. 2sec
5) BARRE SON Anime ligne d'étoiles verticale, aller, retour et stop. (interactif)
6) BARRE TEMPS Anime ligne Etoiles jaunes horizontales. - Coupez le temps entre les étoiles ! (interactif)

Un avis ? jean Yves ?

LE TALISMAN

by SergeV » Tue Sep 23, 2025 8:49 am

1) APPARITION talisman "BING" cloche (3 sec)
2) MINUTEUR SON ENREGISTREMENT (4sec)
3) MODE CHOIX MANUEL(1h) ?
Attachments
animation-talisman-manuel.png
animation-talisman-manuel.png (84.45 KiB) Viewed 61 times
animation-talisman-minuteur-only.png
animation-talisman-minuteur-only.png (777.49 KiB) Viewed 64 times
talisman_anim pnga.png
talisman_anim pnga.png (884.81 KiB) Viewed 89 times

Re: ANIM ORAVOX

by Marcel » Tue Sep 23, 2025 7:02 am

Pour les animations, j'ai une proposition qui pourrait convenir à tout le monde. Les animations sont faites dans After Effects et exportées au format Lottie grâce à des plugins comme Bodymovin ou LottieFiles. Doc : https://github.com/airbnb/lottie/blob/m ... effects.md

Avantages :
- Visuel fidèle au design
- Image vectorielle
- Fichier très léger par rapport aux PNG
- Faible complexité au niveau du code
- Cross-platform (web, iOS, Android, desktop ...)

Inconvénients :
- Compatibilité avec les anciennes (mais très anciennes) versions des navigateurs
- Peut être lourd pour le CPU si l'animation est très complexe

Dites-moi ce que vous en pensez. Pour moi, cela résoudrait nos problèmes d'animation, même la barre de progression.

Apparition + minuteur talisman

by SergeV » Mon Sep 22, 2025 4:35 pm

Apparition talisman avec minuteur
Attachments
animation-talisman-minuteur.png
animation-talisman-minuteur.png (1.83 MiB) Viewed 96 times

Re: ANIM ORAVOX

by MyQ » Thu Sep 04, 2025 11:07 am

All Good, thanx 4 the update

Re: ANIM ORAVOX

by CPAS » Thu Sep 04, 2025 10:54 am

Excuse me, Myq — you are not hallucinating. We talked about that, but I didn’t understand correctly at the time. I wasn’t in a good state to think clearly about a solution for the animation because I was upset that Serge didn’t seem to recognize the problems I’d raised. I think we need to work in better conditions: if we can’t enjoy the work, we should do something else.

I don’t need a plugin system because I don’t want to upgrade the Oravox player. I just want to maintain and enjoy the current system and wait for a successor — someone who will follow a leader without question.

Re: ANIM ORAVOX

by MyQ » Thu Sep 04, 2025 8:20 am

I am sorry guys I have had my head, in this <canvas> thing that Xavier seems to forget our conversation about same where we agreed a plugin could be made, but Xavier did not want to get into. It was further agreed I would try to find a solution, that is what i have been doing. I dug deeper into this problem and discovered a work around, I was forced by serge to make the post that is causing so much confusion, it has never been my habit of posting on bb's i don't see the need when the person is right there.

the solution to using <canvas> as Xavier wants to, is to transform the given anim as it is, the same as always into a running anim canvas can use, in working prototype it preserves timing perfectly, basically a clone, this has been tested using <canvas>. For Xavier all he needs to do is use a 'directory' instead of 'filename' no code changes, full control from java-script if needed once completed will create and upload and store to server the processed anim where Xavier can pick it up automatically, if offline, it will wait until your online again and retry. It is designed to be local or server based, due to request from serge.

So, Xavier, have u changed your mind, is it all a waste of time? Am i hallucinating?
[google]
Je suis désolé, je me suis un peu embêté avec cette histoire de <canvas>. Xavier semble avoir oublié notre conversation à ce sujet, où nous avions convenu de créer un plugin, mais Xavier n'a pas voulu s'y intéresser. Il a ensuite été convenu que j'essaierais de trouver une solution, et c'est ce que j'ai fait. J'ai creusé le problème et trouvé une solution. Serge m'a forcé à publier ce message qui sème tant de confusion. Je n'ai jamais eu l'habitude de poster sur des forums de discussion, je n'en vois pas l'utilité quand la personne est là.

La solution pour utiliser <canvas> comme le souhaite Xavier est de transformer l'animation donnée telle quelle, comme toujours, en une animation opérationnelle que Canvas peut utiliser. Dans un prototype fonctionnel, le timing est parfaitement préservé, c'est un clone. Cela a été testé avec <canvas>. Pour Xavier, il suffit d'utiliser un « répertoire » au lieu d'un « nom de fichier ». Aucun changement de code, contrôle total depuis Javascript si nécessaire. Une fois l'opération terminée, l'animation traitée sera créée, téléchargée et stockée sur le serveur, où Xavier pourra la récupérer automatiquement. Si vous êtes hors ligne, l'animation attendra votre reconnexion avant de réessayer. L'application est conçue pour être locale ou basée sur le serveur, suite à une demande de Serge.

Alors, Xavier, as-tu changé d'avis ? Est-ce une perte de temps ? Ai-je des hallucinations ?

Re: ANIM ORAVOX

by SergeV » Wed Sep 03, 2025 10:50 pm

Même moi je comprend pas.. pourtant je comprend rien mais la je comprend.. que je comprend rien a Miq ?

a Xavier :
Remarque importante ; au fait je t'ai remis les images au format 612x995 ? depuis le début? j"avais pas vue ton format donné ... zut ou pas zut?
pour l'ombre de la coques sur le fond qui ce vois sur l'ecran doit d'disparaitre sur l'écran et donc nous devons calqué l'ombre exterieur de la coque, calque de fond, en premier.. tu vois ce que je veux dire choux.
je te met le calque "aa coque de fond" dans les autres poster

serge

Re: ANIM ORAVOX

by JYS » Wed Sep 03, 2025 7:27 pm

Not sure what you meant MiQ.
Will the html canvas option bring its problems too?

If i understand more or less, you'll be de- and recompose the apng format into some other format that lets html or whatever other language regain controlability over its playing sequences?

Re: ANIM ORAVOX

by CPAS » Wed Sep 03, 2025 5:24 pm

oui j'ai pas bien compris non plus l'intervention de myq, je suppose que c'est une erreur de traduction

l'élément canvas est très bien adapté pour des animations complexes et synchronisées, mais c'est un outil de bas niveau (beaucoup de controle, très complexe) en javascript donc ca nécessite une certaine maitrise

du coup jean-yves comme tu viens pas cette semaine je vais rester aussi à la maison, fais signe quand t'as un créneau si tu veux qu'on se capte à la providence

Re: ANIM ORAVOX

by JYS » Wed Sep 03, 2025 12:07 pm

"Le problème se situe dans Canvas."

Canvas or not Canvas? Je suis un peu perdu là.
Je ne saurais hélas pas passer cette semaine.
De toutes façons je vais voir un peu comment fonctionne l'élément canvas en html.

Re: ANIM ORAVOX

by MyQ » Tue Sep 02, 2025 10:01 am

[google]
Le problème se situe dans Canvas. Selon le navigateur de l'utilisateur, pour la plupart des navigateurs, lors du chargement du fichier .png, le navigateur effectue deux opérations :
1. L'image s'ouvre et s'exécute dans un nouvel onglet, parfois visible, parfois invisible.
2. Seule la première image est extraite, sans chronométrage, au format .json ou autre.

Je développe un outil unique qui consiste à glisser-déposer ou à sélectionner un fichier PNG, à extraire toutes les données et à créer les images et les données .json dans une image virtuelle. Cela permettra à <canvas> de fonctionner normalement, avec un contrôle JavaScript complet.

Si j'y parviens, nous pourrons contourner ce problème.

Je vous tiendrai informé.

Re: ANIM ORAVOX

by CPAS » Tue Sep 02, 2025 9:57 am

Salut — la migration vers Canvas demandera une quantité de code que je ne peux pas prendre en charge. À ma connaissance, il n’existe pas de mécanisme permettant de « déposer » du code qui s’activerait automatiquement comme un plugin dans l’API Canvas.

Je peux toutefois préparer une partie du travail : je mettrai en place un contexte Canvas aux dimensions du lecteur, prêt à être utilisé pour le dessin. Ensuite, la personne qui voudra (et saura) écrire les instructions de dessin en JavaScript pourra réimplémenter le lecteur en langage bas niveau.

EDIT. voilà c'est intégré et aux bonnes dimensions, un espace de 610 par 987 pixels est disponible pour dessiner dans l'espace intérieur de l'écran Oravox (les bords bruns).

Code: Select all

'use strict';

const TEMPLATE_URL = new URL('./oravox-player.html', import.meta.url).href;
const STYLE_URL    = new URL('./oravox-player.css',  import.meta.url).href;

export default class OravoxPlayer extends HTMLElement {
  constructor() {
    super();
    this._shadow = this.attachShadow({ mode: 'open' });
    this.state = { chapter: '001', currentTime: 0, objects: [] };
    this._lastSave = Date.now();
    this._rec = { recorder: null, stream: null, chunks: [], aborted: false, active: false };
    this._sheetIndex = 0;
  }

  _norm(s) {
    return String(s || '').toLowerCase()
      .normalize('NFD')
      .replace(/\p{Diacritic}/gu, '')
      .replace(/[^\p{L}\p{N}\s]+/gu, ' ')
      .replace(/\s+/g, ' ')
      .trim();
  }

  async connectedCallback() {
    const params = new URLSearchParams(location.search);
    this._storyId = params.get('story') || 'empty';

    const resp = await fetch(`/api/progress.php?story=${encodeURIComponent(this._storyId)}`, { credentials: 'include' });
    if (resp.status === 401) return void location.replace('/login.html');
    if (resp.ok) {
      const data = await resp.json();
      if (data.state_json) this._initialState = JSON.parse(data.state_json);
    }

    try {
      const [html, css] = await Promise.all([
        fetch(TEMPLATE_URL).then(r => r.text()),
        fetch(STYLE_URL).then(r => r.text())
      ]);
      this._shadow.innerHTML = `<style>${css}</style>${html}`;

      const s = this._shadow;
      this._audio     = s.querySelector('audio');
      this._audio.preload = 'metadata';
      this._buttons   = s.getElementById('buttons');
      this._buttons2  = s.getElementById('buttons2');
      this._interface = s.getElementById('interface');
      this._synopsis  = s.getElementById('synopsis');
      this._play      = s.getElementById('play');
      this._stop      = s.getElementById('stop');
      this._back      = s.getElementById('back');
      this._restart   = s.getElementById('restart');
      this._quit       = s.getElementById('quit');
      this._bar       = s.getElementById('bar');
      this._fill      = s.getElementById('fill');
      this._cover     = s.getElementById('cover');
      this._choices   = s.getElementById('choices');
      this._btnA      = s.getElementById('btnA');
      this._btnB      = s.getElementById('btnB');
      this._btnC      = s.getElementById('btnC');
      this._chrono    = s.getElementById('chrono');
      this._recording = s.getElementById('recording');
      this._timer     = s.getElementById('timer');
      this._canvas    = s.getElementById("canvas");
      this._ctx       = this._canvas.getContext("2d");

      this._audio.addEventListener('ended', async () => {
        this._choices.style.display = '';
        this._recording.style.display = '';
        this._timer.style.display = '';
        this._chrono.textContent = '0:00';

        new Audio('/assets/audio/jingle.mp3').play().catch(() => {});

        this._rec.aborted = false;
        this._rec.active = false;
        this._rec.chunks = [];

        try {
          const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
          const mediaRecorder = new MediaRecorder(stream);
          this._rec.stream = stream;
          this._rec.recorder = mediaRecorder;
          this._rec.active = true;
          console.log('[ enregistrement en cours ]');

          mediaRecorder.addEventListener('dataavailable', e => {
            if (e.data && e.data.size > 0) this._rec.chunks.push(e.data);
          });

          mediaRecorder.addEventListener('stop', async () => {
            const aborted = this._rec.aborted;
            this._recording.style.display = 'none';
            this._timer.style.display = 'none';
            this._rec.active = false;
            this._rec.stream?.getTracks().forEach(t => t.stop());
            this._rec.stream = null;

            if (aborted) {
              this._rec.chunks = [];
              return;
            }

            const audioBlob = new Blob(this._rec.chunks, { type: 'audio/webm' });
            this._rec.chunks = [];
            console.log('[ envoi du blob au serveur ]');

            try {
              const resp = await fetch('/api/whisper.php', {
                method: 'POST',
                headers: { 'Content-Type': 'audio/webm' },
                body: audioBlob
              });
              if (!resp.ok) throw new Error('HTTP ' + resp.status);

              const { text = '' } = await resp.json();
              console.log(text || '[ aucune transcription reçue ]');

              const heard = this._norm(text);
              const heardSet = new Set(heard ? heard.split(' ') : []);
              const currentId = this.state.chapter;
              const nextIds = this.storyMeta.chapters[currentId]?.choices || [];

              const matchedId = nextIds.find(id => {
                const cmds = this.storyMeta.chapters[id]?.commands || [];
                return cmds.some(cmd => {
                  const c = this._norm(cmd);
                  return c && c.split(' ').some(tok => heardSet.has(tok));
                });
              });

              if (matchedId) {
                const chosenIndex = nextIds.indexOf(matchedId);
                await this._choose(chosenIndex);
              } else {
                console.log(this.storyMeta.chapters[currentId]?.label || 'Label manquant');
              }

            } catch (err) {
              console.error('whisper.php error:', err);
            }
          });

          mediaRecorder.start();
          setTimeout(() => { mediaRecorder.stop(); }, 3000);

        } catch (err) {
          console.error('getUserMedia/MediaRecorder error:', err);
          this._recording.style.display = 'none';
          this._timer.style.display = 'none';
        }
      });

      this._audio.addEventListener('timeupdate', () => {
        const cur = this._audio.currentTime || 0;
        const dur = this._audio.duration || 0;
        if (Number.isFinite(dur) && dur > 0) {
          this._fill.style.width = ((cur / dur) * 100) + '%';
          const rem = Math.max(0, dur - cur);
          const minutes = Math.floor(rem / 60);
          const seconds = String(Math.floor(rem % 60)).padStart(2, '0');
          this._chrono.textContent = `${minutes}:${seconds}`;
        } else {
          this._fill.style.width = '0%';
          this._chrono.textContent = '--:--';
        }
        if (Date.now() - this._lastSave > 2000) {
          this._lastSave = Date.now();
          this._saveState();
        }
        this.state.currentTime = cur;
      });

      this._audio.addEventListener('play', () => {
        this._play.classList.add('active');
        this._stop.classList.remove('active');
      });
      this._audio.addEventListener('pause', () => {
        this._play.classList.remove('active');
        this._stop.classList.add('active');
      });
      this._audio.addEventListener('error', e => console.error('Audio playback error:', e));

      this._play.addEventListener('click', () => {
        if (!this._audio.ended) {
          if (this._audio.paused) this._audio.play();
          else this._audio.currentTime = Math.min(this._audio.duration, this._audio.currentTime + 5);
        }
      });
      this._stop.addEventListener('click', () => this._audio.pause());
      this._back.addEventListener('click', () => {
        this._abortRecordingIfAny();
        this._recording.style.display = 'none';
        this._timer.style.display = 'none';
        this._choices.style.display = 'none';
        this._audio.currentTime = Math.max(0, this._audio.currentTime - 5);
      });
      [this._btnA, this._btnB, this._btnC].forEach((btn, idx) => {
        btn.addEventListener('click', async () => {
          this._abortRecordingIfAny();
          await this._choose(idx);
        });
      });

    this._restart.addEventListener('click', async () => {
      this._abortRecordingIfAny();
      this._recording.style.display = 'none';
      this._timer.style.display = 'none';
      this._choices.style.display = 'none';
      this.state.chapter = '001';
      this.state.currentTime = 0;
      await this._loadChapter(this.state.chapter, 0);
      this._audio.play();
    });

    this._quit.addEventListener('click', () => {
      this._abortRecordingIfAny();
      this._saveState();
      location.assign('/');
    });

      window.addEventListener('beforeunload', () => {
        const payload = { story: this._storyId, state_json: JSON.stringify(this.state) };
        navigator.sendBeacon('/api/progress.php', new Blob([JSON.stringify(payload)], { type: 'application/json' }));
      }, { once: true });

      const meta = await fetch(`/assets/stories/${this._storyId}/story.json`);
      this.storyMeta = await meta.json();
      this._cover.src = `/assets/stories/${this._storyId}/cover.avif`;
      if (this._initialState) Object.assign(this.state, this._initialState);
      await this._loadChapter(this.state.chapter, this.state.currentTime);

    } catch (err) {
      console.error('Init OravoxPlayer error:', err);
    }

    this._buttons2.style.display = 'none';
    this._cover.addEventListener('click', () => {
      this._sheetIndex = (this._sheetIndex + 1) % 2;
      console.log('sheet:', this._sheetIndex);
      if (this._sheetIndex == 0) {
        this._cover.src = `/assets/stories/${this._storyId}/cover.avif`;
        this._interface.src = `/components/oravox-player/interface.avif`;
        this._buttons.style.display = '';
        this._synopsis.textContent = '';
        this._bar.style.backgroundImage = 'url("/components/oravox-player/thumb_empty.png")';
        this._buttons2.style.display = 'none';
      } else if (this._sheetIndex == 1) {
        this._cover.src = `/components/oravox-player/cover2.png`;
        this._buttons.style.display = 'none';
        this._synopsis.textContent = 'SYNOPSIS';
        this._interface.src = `/components/oravox-player/interface2.avif`;
        this._bar.style.backgroundImage = 'none';
        this._buttons2.style.display = '';
      }
    });

    // CANVAS - C'EST ICI QUE CA SE PASSE
    const path = new Path2D();
    path.arc(this._canvas.width / 2, this._canvas.height / 2, 256, 0, Math.PI * 2);
    this._ctx.fillStyle = '#C938';
    this._ctx.fill(path);

  }

  async _choose(choiceIndex) {
    const chap = this.storyMeta.chapters[this.state.chapter];
    const next = chap.choices?.[choiceIndex];
    if (!next) return;
    this.state.chapter = next;
    this.state.currentTime = 0;
    await this._loadChapter(next, 0);
    this._audio.play();
  }

  async _loadChapter(chapterId, startTime = 0) {
    console.log("LOG: loadChapter()")
    this._abortRecordingIfAny();
    this._recording.style.display = 'none';
    this._timer.style.display = 'none';
    this._choices.style.display = 'none';

    const chap = this.storyMeta.chapters[chapterId];
    if (!chap) return console.warn('Chapitre introuvable :', chapterId);

    this._audio.src = `/assets/stories/${this._storyId}/${chap.audio}`;
    await new Promise(res => {
      if (Number.isFinite(this._audio.duration)) return res();
      const onMeta = () => { this._audio.removeEventListener('loadedmetadata', onMeta); res(); };
      this._audio.addEventListener('loadedmetadata', onMeta, { once: true });
    });
    try { this._audio.currentTime = startTime; } catch {}

    console.log(chap.label || 'Label manquant');
    this._renderChoice(this._btnA, chap.choices?.[0]);
    this._renderChoice(this._btnB, chap.choices?.[1]);
    this._renderChoice(this._btnC, chap.choices?.[2]);

    this.state.chapter = chapterId;
    this._audio.dispatchEvent(new Event('pause'));
    this._saveState();
  }

  _renderChoice(button, nextId) {
    if (!nextId) {
      button.style.display = 'none';
      return;
    }
    const target = this.storyMeta.chapters[nextId];
    button.textContent = target?.label ?? nextId;
    button.style.display = '';
  }

  _saveState() {
    console.log("LOG: saveState()")
    fetch('/api/progress.php', {
      method: 'POST',
      credentials: 'include',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ story: this._storyId, state_json: JSON.stringify(this.state) })
    }).catch(err => console.error('Erreur _saveState :', err));
  }

  _abortRecordingIfAny() {
    console.log("LOG: abortRecordingIfAny()")
    if (this._rec.active) {
      this._rec.aborted = true;
      this._rec.recorder?.stop();
      this._rec.stream?.getTracks().forEach(t => t.stop());
      this._rec.active = false;
      this._recording.style.display = 'none';
      this._timer.style.display = 'none';
      this._rec.chunks = [];
    }
  }
}

customElements.define('oravox-player', OravoxPlayer);

Re: ANIM ORAVOX

by SergeV » Tue Sep 02, 2025 12:00 am

Mick propose aussi par Canvas. De déposer l'anime sur le serveur et pas sur l'oravox. D'après ce que j'ai compris, avec un lien qui vient s'installer dans le code. c'est possible?

Top