Aller au contenu

Cours 13

Zdog

Zdog est une petite librairie JavaScript pour créer des illustrations pseudo-3D “flat” (sans perspective) et animées, à partir de formes simples (cercles, rectangles, cylindres, etc.).

Sa particularité est que les objets existent en 3D, mais sont rendus comme des formes 2D plates, ce qui donne un look illustratif plutôt qu’un rendu 3D réaliste.

Zdog n’est pas une vraie librairie 3D comme threejs, mais plutôt un petit moteur pseudo-3D très simplifié.

Installation

index.html
<html>
  <head>

    <script type="importmap">
      {
        "imports": {
          "zzz": "https://esm.sh/zdog"
        }
      }
    </script>
    <script type="module" src="./src/js/zdog.js"></script>

  </head>
  <body>

    <canvas class="zdog-canvas"></canvas>

  </body>
</html>
styles.css
.zdog-canvas {
  width: 90vw;
  height: 90vh;
}
zdog.js (exemple le plus simple)
import Zdog from "zzz";

const illo = new Zdog.Illustration({
    element: ".zdog-canvas",
    resize: true, // canvas responsive
});

new Zdog.Ellipse({
    addTo: illo,
    diameter: 100,
    stroke: 40,
    color: "#E49",
});

illo.updateRenderGraph(); // 👈 Dessine dans le canvas

Interactivité

zdog.js (exemple le plus simple)
import Zdog from "zzz";

const illo = new Zdog.Illustration({
    // ...
    dragRotate: true, // 👈
});

// 👇 Nécessaire pour l'interactivité
function animate() {
    illo.updateRenderGraph();
    requestAnimationFrame(animate);
}
animate();

Bloquer un axe

Fixe la rotation de l'axe x à 0
import Zdog from "zzz";

const illo = new Zdog.Illustration({
    // ...
    dragRotate: true,
    onDragMove: function() {
        this.rotate.x = 0;
    },
});

Animation

zdog.js (exemple le plus simple)
import Zdog from "zzz";

const illo = new Zdog.Illustration({
    // ...
});

function animate() {
  illo.rotate.y += 0.03; // 👈 360° = 2π
  illo.rotate.x += 0.03; // 👈 360° = 2π
  illo.updateRenderGraph();
  requestAnimationFrame(animate);
}
animate();

Formes

Les formes zdog (Rect, RoundedRect, Ellipse, Polygon, Shape, Hemisphere, Cone, Cylinder, Box) sont pour la plupart assez simples à mettre en place. Il suffit de consulter la documentation à cet effet.

AnimeJS

Yep ! Ça se fait. Et assez facilement même.

Avec AnimeJS, on peut animer des variables. Ces mêmes variables seront utilisées pour changer les transformations Zdog.

import Zdog from "zzz";
import { animate, utils } from 'animejs';

let illo = new Zdog.Illustration({
  element: ".zdog-canvas",
  resize: true
});

let box = new Zdog.Box({
  addTo: illo,
  // ...
});


const rotationAnimation = { x: 0, y: 0, z: 0 };
const getRandomRotation = () => utils.random(0, Math.PI * 2, 2);

animate(rotationAnimation, {
  x: getRandomRotation,
  y: getRandomRotation,
  z: getRandomRotation,
  duration: 2000,
  loop: true,
  ease: "outElastic",
  onUpdate: () => {
    box.rotate.x = rotationAnimation.x;
    box.rotate.y = rotationAnimation.y;
    box.rotate.z = rotationAnimation.z;
  },
  onLoop: (self) => {
    self.refresh();
  }
});

function animateZDOG() {
  illo.updateRenderGraph();
  requestAnimationFrame(animateZDOG);
}

animateZDOG();

Tone.js

Tone.js est une librairie JavaScript pour créer et manipuler du son dans le navigateur. Elle permet de générer des sons avec des synthétiseurs, de jouer des fichiers audio, d'appliquer des effets sonores et de créer des séquences musicales.

Installation

index.html
<html>
  <head>

    <script type="importmap">
      {
        "imports": {
          "tone.js": "https://esm.sh/tone@15.1.22",
        }
      }
    </script>
    <script type="module" src="./src/js/tonejs.js"></script>

  </head>
  <body>

    <button></button>

  </body>
</html>
tonejs.js
import * as Tone from "tone.js";

document.querySelector("button").addEventListener("click", async () => {
  await Tone.start();

  const synth = new Tone.Synth().toDestination();
  synth.triggerAttackRelease("C4", "8n");
});

Quelques notions importantes

Notation anglo-saxonne :

C D E F G A B (Do Ré Mi Fa Sol La Si)
Ex: C4, le 4 représente l'octave

Notation rythmique :

  • 1n : ronde
  • 2n : blanche (demi-note)
  • 4n : noire (quart de note)
  • 8n : croche (huitième de note)
  • 16n : double-croche (seizième de note)

Instruments

tonejs.js
import * as Tone from "tone.js";

document.querySelector("button").addEventListener("click", async () => {
  await Tone.start();

  const synth = new Tone.Synth().toDestination();
  synth.triggerAttackRelease("C4", "8n");

  const fmSynth = new Tone.FMSynth().toDestination();
  fmSynth.triggerAttackRelease("C3", "4n");

  const drum = new Tone.MembraneSynth().toDestination();
  drum.triggerAttackRelease("C2", "4n");

  // ...
});

Liste des instruments et leurs paramètres.

Polyphonie / accords

tonejs.js
import * as Tone from "tone.js";

document.querySelector("button").addEventListener("click", async () => {
  await Tone.start();

  const synth = new Tone.PolySynth(Tone.Synth).toDestination();
  synth.triggerAttackRelease(["C4", "E4", "G4"], "4n");
});

Suite

tonejs.js
import * as Tone from "tone.js";

const synth = new Tone.Synth().toDestination();

document.querySelector("button").addEventListener("click", async () => {
  await Tone.start();

  const now = Tone.now();
  synth.triggerAttackRelease("C4", "8n", now + 0.0);
  synth.triggerAttackRelease("D4", "8n", now + 0.25);
  synth.triggerAttackRelease("E4", "8n", now + 0.5);
  synth.triggerAttackRelease("F4", "8n", now + 0.75);
  synth.triggerAttackRelease("G4", "8n", now + 1.0);
  synth.triggerAttackRelease("A4", "8n", now + 1.25);
  synth.triggerAttackRelease("B4", "8n", now + 1.5);
  synth.triggerAttackRelease("c5", "2n", now + 1.75);
});

Fichiers

tonejs.js
import * as Tone from "tone.js";

const player = new Tone.Player("https://tonejs.github.io/audio/berklee/gong_1.mp3").toDestination();

document.querySelector("button").addEventListener("click", async () => {
  await Tone.start();

  Tone.loaded().then(() => {
      player.start();
  });
});

Base de données de fichiers audio gratuits.

Effets

tonejs.js
import * as Tone from "tone.js";

document.querySelector("button").addEventListener("click", async () => {

  const now = Tone.now();

  // Synth -> Delay -> Reverb -> 🔈
  const reverb = new Tone.Reverb(2).toDestination();
  const delay = new Tone.FeedbackDelay("8n", 0.5).connect(reverb);
  const synthWithReverb = new Tone.Synth().connect(delay);
  synthWithReverb.triggerAttackRelease("A4", "2n", now + 5);
});

Liste des effets et leurs paramètres.

.toDestination()

Imaginez le .toDestination() comme si on disait que c'était branché dans le haut-parleur 🔈.

Typed.js

Typed.js est une librairie JavaScript qui simule la frappe de texte au clavier. Elle affiche du texte lettre par lettre, comme si quelqu'un le tapait en temps réel, avec des options pour contrôler la vitesse, les pauses et les boucles.

Installation

npm i typed.js
index.html
<html>
  <head>

    <script type="importmap">
      {
        "imports": {
          "typed.js": "./node_modules/typed.js/dist/typed.module.js",
        }
      }
    </script>
    <script type="module" src="./src/js/typedjs.js"></script>

  </head>
  <body>

    <p>
        <span id="typedjs-elem"></span>
    </p>

  </body>
</html>
typedjs.js
import Typed from 'typed.js';

new Typed("#typedjs-elem", {
  strings: [
    "Typed.js est une <strong>librairie</strong> JavaScript.",
    "Elle <em>simule la frappe</em> de phrases, comme si quelqu’un les tapait au clavier."
  ],
  typeSpeed: 50,
  loop: true
});

Snippet du jour

npm i tone-visualizer
<!DOCTYPE html>
<html lang="fr">
<head>

    <script src="https://cdn.jsdelivr.net/npm/p5@2.1.1/lib/p5.js"></script>

    <script type="importmap">
      {
        "imports": {
          "tone.js": "https://esm.sh/tone@15.1.22",
          "tone-visualizer": "./node_modules/tone-visualizer/dist/visualizer.esm.js"
        }
      }
    </script>

    <script type="module" src="./src/js/script.js"></script>
</head>
<body>

    <div class="visualizer"></div>

</body>
</html>
import * as Tone from "tone.js";
import { ToneVisualizer } from "tone-visualizer";

document.body.addEventListener("click", async () => {
    await Tone.start();

    const fmSynth = new Tone.FMSynth().toDestination();
    const viz = new ToneVisualizer('.visualizer', fmSynth, {Tone});
    fmSynth.triggerAttackRelease("C3", "4n");
});

Exercices

Exercice - Tone.js
La cinquième

Exercice - Zdog
Éclipse

TP2

TP
HUD