Viewer 3D de Molécules

Vue d'ensemble

Visualiseur 3D interactif de molécules chimiques, accessible via /projects/molecule-viewer. Combine un catalogue de molécules prédéfinies avec une recherche libre via l'API PubChem, le tout rendu en WebGL avec Three.js/React Three Fiber.

Public cible : étudiants en chimie, chercheurs, curieux de sciences. Contexte : projet personnel démontrant l'intégration de Three.js dans Next.js (App Router) et la consommation d'une API scientifique externe.


Ressources clés

Stack technique

LibUsage
React 19 + Next.js App RouterRendu, routing
Three.jsRendu 3D WebGL bas niveau
@react-three/fiberAbstraction React de Three.js
@react-three/dreiHelpers R3F (OrbitControls, etc.)
TypeScript strictTypage des atomes, liaisons, settings
PubChem REST APIRécupération de structures moléculaires au format JSON3D
Tailwind CSS v4Interface UI

MoleculeScene est chargé en dynamic avec ssr: false — Three.js requiert le DOM navigateur, incompatible avec le SSR Next.js.


Architecture

src/app/projects/molecule-viewer/
  page.tsx           # Interface principale : sélection, recherche, paramètres, mode mesure
  MoleculeScene.tsx  # Canvas R3F : rendu 3D des atomes et liaisons
  layout.tsx         # Metadata Next.js
  opengraph-image.tsx

Flux de données

page.tsx
  ├── Catalogue MOLECULES (statique inline) → sélection par défaut
  ├── Recherche PubChem → fetch → parse → SceneMolecule
  └── SceneMolecule/SceneSettings → props vers MoleculeScene
                                         └── Canvas R3F
                                               ├── Sphères (atomes)
                                               ├── Cylindres (liaisons)
                                               └── OrbitControls

Types partagés (MoleculeScene.tsx)

interface SceneAtom {
  element: string;   // "C", "H", "O", etc.
  position: [number, number, number];
  index: number;
}

interface SceneMolecule {
  atoms: SceneAtom[];
  bonds: [number, number][];  // paires d'indices d'atomes
}

interface SceneSettings {
  accentColor: string;
  cameraZ: number;
  measureMode: boolean;
}

Fonctionnalités

Catalogue de molécules prédéfinies

10 molécules hardcodées dans MOLECULES (tableau as const) avec pour chacune :

  • id — identifiant interne
  • name / formula — affichage FR (+ table MOLECULE_EN pour les noms/descriptions EN)
  • cid — identifiant PubChem pour le fetch des coordonnées 3D
  • molarMass — masse molaire affichée
  • cameraZ — distance initiale caméra (adaptée à la taille de la molécule)
  • accentColor — couleur d'accent de la fiche (différente par molécule)
  • description — texte chimique descriptif (FR inline, EN dans MOLECULE_EN)

Molécules disponibles : Eau, Éthanol, Benzène, Caféine, Aspirine, Dopamine, Glycine, Acide pyruvique, Propionitrile, Nicotinamide.

Récupération des structures 3D (PubChem)

Lors de la sélection d'une molécule (catalogue ou recherche), la page fetch :

https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/cid/{cid}/JSON?record_type=3d

La réponse est parsée pour extraire :

  • Les atomes (atoms.element, coords[0].conformers[0] → x/y/z)
  • Les liaisons (bonds.aid1[i], bonds.aid2[i] → paires d'indices)

Recherche libre PubChem

Un champ de recherche permet de chercher n'importe quelle molécule par nom (en anglais). Le flux :

  1. Fetch https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/name/{query}/cids/JSON → liste de CIDs
  2. Fetch du premier CID trouvé en mode 3D
  3. Mise à jour de la scène

Affichage d'un état de chargement // recherche en cours… et d'un message d'erreur si aucun résultat.

Rendu 3D (MoleculeScene)

  • Atomes : sphères Three.js avec coloration CPK (C=gris, H=blanc, O=rouge, N=bleu, S=jaune, etc.)
  • Liaisons : cylindres entre les atomes liés
  • OrbitControls : rotation (drag), zoom (scroll), déplacement (clic droit)
  • Éclairage : lumière ambiante + directionnelle

Mode mesure

Activé via le bouton ⟷ Mesure. En mode mesure :

  • Le clic sur deux atomes successifs calcule et affiche la distance interatomique en Angströms (Å)
  • Implémenté via un useReducer gérant l'état selectedAtoms: [number, number] | [number]

Paramètres de scène

Contrôlés depuis page.tsx et passés en props :

  • showHydrogens — affichage/masquage des hydrogènes
  • bondStyle — style de liaisons (stick / ball-and-stick)
  • accentColor — couleur d'accent héritée de la molécule sélectionnée

i18n

  • Toutes les chaînes UI sont dans i18n/fr.ts et i18n/en.ts sous la clé molecule_viewer.*
  • Le composant importe { fr as frStrings } et { en as enStrings } directement (pas useLang()) car il possède son propre toggle de langue indépendant du contexte global
  • Les noms et descriptions des molécules prédéfinies : FR inline dans MOLECULES, EN dans MOLECULE_EN (données, pas UI)
  • Les molécules issues de PubChem n'ont pas de traduction (données brutes de l'API)
  • Les strings avec paramètres (ex. "// {n} atomes") utilisent .replace("{n}", ...) dans le JSX

Points d'attention

  • SSR : MoleculeScene doit absolument être chargé avec dynamic(..., { ssr: false }). Three.js accède au DOM (window, canvas) au montage.
  • PubChem rate limiting : l'API publique n'a pas de clé d'authentification mais limite les requêtes. En cas d'usage intensif, envisager un cache côté serveur.
  • Coordonnées 3D : PubChem ne fournit pas toujours les coordonnées 3D (conformères) pour toutes les molécules. En cas d'absence, le fetch échoue silencieusement et affiche // erreur.
  • Recherche en anglais uniquement : l'API PubChem répond principalement aux noms IUPAC anglais. Le hint UI le précise.
  • Mémoire WebGL : chaque changement de molécule recrée la scène Three.js. Sur mobile, les contextes WebGL multiples peuvent être problématiques.

Évolutions possibles

  • Affichage du nom IUPAC et de la formule brute pour les molécules recherchées
  • Mode "comparer deux molécules" (split screen)
  • Coloration par électronégativité ou charge partielle
  • Export de capture d'écran de la scène 3D (canvas.toDataURL())
  • Cache localStorage des CIDs récemment consultés
  • Mode "surfaces de van der Waals" (sphères aux rayons CPK réels)
  • Annotation des liaisons (affichage de la longueur en Å au survol)