Retour

Cartes musicales 3D

Un espace musical interactif en plein écran : un personnage Tripo se tient au centre, entouré de six panneaux de disques en verre réellement jouables, disposés en constellation 3D irrégulière. Lorsqu’un morceau est sélectionné, son panneau quitte l’espace, vole au premier plan et se pose en bas sous la forme d’un lecteur 2D.

Auteur: Theodore
Essayer en direct
Cartes musicales 3DEssayer en direct

À propos de ce projet

Les six panneaux sont de véritables géométries WebGL intégrées à la Scene — ils ont une épaisseur et une courbure, masquent le personnage et sont masqués par lui, tandis que leur ordre de profondeur reste correct sous tous les angles. Ce ne sont pas des cartes DOM flottant au-dessus d’un Canvas.

Toute l’interaction repose sur une répartition claire : la 3D sert à explorer, la 2D à contrôler. Les panneaux prennent en charge la navigation et la sélection, dérivent autour du personnage et tournent au gré des gestes ; les commandes de lecture proprement dites appartiennent à l’interface stable en screen space située en bas. Choisir un morceau n’est pas un changement d’état, mais un passage de relais continu — le panneau lui-même descend en volant pour devenir le lecteur ; lorsqu’un autre titre est choisi, l’ancien regagne son emplacement 3D d’origine.

Points forts

  1. Faire glisser l’espace vide met les cartes musicales en rotation autour du personnage, puis les laisse poursuivre sur leur inertie ; faire glisser le personnage ne fait tourner que lui, sans toucher à la caméra ni aux panneaux. Les deux ensembles dérivent lentement en sens opposés — c’est ce mouvement contraire qui donne à l’agrégat l’allure d’un corps en orbite plutôt que d’un simple décor.
  2. Un clic libère un panneau de l’espace 3D : il passe devant le personnage et se déploie en lecteur horizontal au bas de l’écran. Lorsqu’un autre panneau est choisi, les deux sont simultanément en vol — l’ancien se replie exactement dans son emplacement d’origine tandis que le nouveau s’avance.
  3. La molette déplace la caméra en profondeur entre 4.6 et 16 unités du monde : en avançant, les panneaux du premier plan débordent du cadre ; en reculant, tout l’espace se rassemble en une constellation musicale vue d’en haut.
  4. Le cadre à quatre coins du curseur personnalisé se verrouille sur le quad réellement projeté de chaque panneau — les crochets se placent sur les véritables angles de perspective et pivotent avec l’inclinaison du panneau.

Analyse technique

  • Ressources 3D · L’export Tripo intact

    Artist.glb est livré exactement tel qu’il est exporté depuis Tripo : 59 MB, 1.02M vertices et une texture de couleur de base de 8192² — aucune décimation, aucun redimensionnement, tous les détails d’origine. Le coût est assumé (~350 MB VRAM après génération du mipmap, un million de vertices redessinés à chaque frame) et deux choix permettent de le maîtriser : le maillage lourd est exclu du raycasting — un million de triangles à chaque mouvement du pointeur bloqueraient le thread principal — et remplacé par une capsule invisible dimensionnée d’après les limites du modèle ; comme l’export ne contient aucun clip d’animation, le personnage reçoit par ailleurs une animation idle au niveau du groupe (un lent balancement et un millimètre de respiration), plutôt qu’un squelette artificiel.

    Une pipeline meshopt dans scripts/ ramène le même fichier à 2.9 MB ; le modèle est mesuré et normalisé au chargement, ce qui permet de changer de build sans modifier le code.

  • Matériaux · Alléger le matériau volumétrique des exports Tripo

    Les exports Tripo marquent le maillage avec KHR_materials_volume, ce qui produit dans three.js un MeshPhysicalMaterial doté d’un chemin transmission/thickness dont cette Scene ne veut pas et dont elle ne peut assumer le coût. Au chargement, chaque matériau est remplacé par MeshStandardMaterial tout en conservant l’ensemble des maps PBR — même rendu, coût supprimé.

    Les ShaderMaterials personnalisés incluent explicitement colorspace_fragment : sans lui, ils écrivent des valeurs linéaires directement dans un framebuffer sRGB et produisent un rendu presque noir.

  • Panneaux musicaux · Une véritable géométrie sur une courbe

    Chaque panneau combine quatre types de géométrie — une face, une bande périphérique extrudée pour créer une véritable épaisseur, une plaque arrière translucide et des quads d’interaction invisibles. Tous partagent le même jeu de buffers en cache ; seule la transformation du groupe varie d’une carte à l’autre. Tous les éléments sont créés à plat puis enroulés autour d’un grand cylindre vertical : la rainure de progression et l’horloge sont intégrées à la même courbe au lieu de lui être rattachées, et le remplissage de progression repose sur un cutoff UV injecté dans un MeshBasicMaterial — mettre un maillage à l’échelle soulèverait son extrémité distante hors de la courbe.

    Le visuel du panneau est réparti entre trois Canvas selon leur fréquence de mise à jour : la face de 1320×680 n’est peinte qu’une fois, la bande temporelle uniquement lorsque la seconde affichée change, et l’icône seulement lorsque l’état de lecture bascule — aucune opération coûteuse dans le render loop. Les six panneaux transparents n’écrivent pas dans le buffer de profondeur et reçoivent à chaque frame une renderOrder par paliers selon leur distance à la caméra, afin que l’occlusion reste correcte sous tous les angles.

  • Relais 3D vers 2D · Une carte devient le lecteur

    Un maillage WebGL ne peut pas devenir un nœud DOM. La continuité repose donc sur trois éléments : un projecteur actualise à chaque frame la boîte en screen space de chaque carte — y compris celles qui sont masquées, car le vol retour doit avoir une destination ; la première frame du panneau DOM reprend exactement le bitmap du Canvas déjà peint pour la texture WebGL de la carte, et non une reconstitution HTML qui ne s’alignerait jamais tout à fait ; enfin, la carte disparaît au cours de cette même frame — deux éléments au même endroit, dont un invisible.

    L’élargissement attend que le vol soit achevé à ~35% — étirer en plein trajet une carte 2:1 pour en faire une barre 11:1 réduirait le visuel en bouillie —, tandis que la trajectoire suit une courbe de Bézier quadratique cintrée sur le côté : une carte qui arrive depuis le coin supérieur gauche contourne ainsi le personnage. La destination est relue à chaque frame : la constellation continue de dériver, et un rect relevé au départ ferait atterrir le panneau à côté de sa carte.