
Il suffit parfois d’une figure très simple pour ouvrir un chantier beaucoup plus vaste.
Le point de départ de Math Art est une construction géométrique composée de points disposés sur un cercle et de segments reliant ces points selon une règle numérique. Au premier regard, on ne voit que des droites. Pourtant, lorsque leur nombre augmente, des courbes apparaissent. Lorsque le multiplicateur évolue, ces courbes se transforment. Et lorsque l’animation accélère tout en conservant une partie des images précédentes, la géométrie commence à produire des formes fluides, presque organiques.
Ce qui devait être une petite expérience mathématique est progressivement devenu un laboratoire de géométrie générative : un moteur WebGL contrôlable à la souris, des paramètres modifiables en temps réel, un système de persistance visuelle et un export vidéo directement depuis le navigateur.
Dans le Homelab, ce projet est aussi un cas d’école : comment passer d’une idée mathématique à une application interactive, la conteneuriser avec Docker, la piloter avec Dockge, l’exposer avec Nginx Proxy Manager et conserver un accès privé via Tailscale.
Objectif du projet : rendre visible une règle mathématique, permettre de la manipuler, puis documenter aussi bien le phénomène que l’infrastructure qui le rend accessible.
1. De l’observation au laboratoire
La première question était presque naïve : comment une collection de segments droits peut-elle donner l’impression de dessiner une courbe ?
Pour le comprendre, j’ai commencé par reconstruire la figure à partir de ses éléments les plus simples :
- un cercle de rayon
R; npoints régulièrement espacés ;- une règle associant chaque point à un autre point ;
- un segment tracé entre les deux.
La première version pouvait être calculée en 2D. Mais très vite, l’intérêt n’était plus seulement de générer une image fixe : il fallait pouvoir modifier n, faire évoluer le multiplicateur m, tourner la scène, zoomer et observer les transitions en temps réel.
C’est là que WebGL est devenu naturel. Le navigateur ne servait plus simplement à afficher une page : il devenait le moteur du laboratoire.
Puis une deuxième observation a changé la direction du projet. En augmentant la vitesse de variation de m, certaines transitions produisaient des formes hypnotiques. Les segments semblaient se transformer en filaments ou en surfaces courbes mouvantes.
Pour rendre ce phénomène perceptible, j’ai ajouté une persistance temporelle : au lieu d’effacer complètement l’image précédente, le moteur en conserve une fraction. Les états successifs s’accumulent alors comme une trace lumineuse.

Cette fonction a naturellement conduit à l’export vidéo : si la transformation est intéressante dans le temps, il faut pouvoir la conserver et la comparer.
2. La règle mathématique de départ
Le moteur commence par répartir n points régulièrement sur un cercle.
Pour le point d’indice k, l’angle est :
[
\theta_k = \frac{2\pi k}{n}
]
Ses coordonnées sont donc :
[
P_k = \left(R\cos\frac{2\pi k}{n},\;R\sin\frac{2\pi k}{n}\right)
]
On choisit ensuite un multiplicateur m. Dans la version discrète classique, le point k est relié au point :
[
k’ = (m k) \bmod n
]
Le modulo joue ici le rôle d’une horloge. Lorsque le calcul dépasse le dernier point, on revient au début du cercle.
Avec n = 10 et m = 2, par exemple :
0 → 0
1 → 2
2 → 4
3 → 6
4 → 8
5 → 0
6 → 2
...
Pour obtenir une animation parfaitement fluide, Math Art utilise aussi une version continue : au lieu de viser uniquement un sommet discret, l’angle θ est envoyé vers :
[
\theta \longmapsto m\theta \pmod{2\pi}
]
Le point d’arrivée reste donc exactement sur le cercle, même lorsque m = 2.173 ou m = 3.624.

3. Pourquoi des droites font-elles apparaître une courbe ?
C’est la partie la plus fascinante du projet.
Prenons un point du cercle à l’angle θ et son point cible à l’angle mθ. La droite passant par deux points d’un même cercle, situés aux angles α et β, peut s’écrire sous la forme :
[
x\cos\left(\frac{\alpha+\beta}{2}\right)
+y\sin\left(\frac{\alpha+\beta}{2}\right)
=R\cos\left(\frac{\alpha-\beta}{2}\right)
]
Ici :
[
\alpha=\theta, \qquad \beta=m\theta
]
La famille de droites devient donc :
[
F(x,y,\theta)=
x\cos\left(\frac{m+1}{2}\theta\right)
+y\sin\left(\frac{m+1}{2}\theta\right)
-R\cos\left(\frac{m-1}{2}\theta\right)=0
]
Une enveloppe est une courbe tangente à chacune des droites de cette famille au voisinage du point correspondant. Pour la trouver, on résout simultanément :
[
F(x,y,\theta)=0
]
et
[
\frac{\partial F}{\partial\theta}=0
]
Après résolution, on obtient :
[
x(\theta)=\frac{R}{m+1}\left(m\cos\theta+\cos(m\theta)\right)
]
[
y(\theta)=\frac{R}{m+1}\left(m\sin\theta+\sin(m\theta)\right)
]
Pour m = 2 :
[
x(\theta)=\frac{R}{3}\left(2\cos\theta+\cos2\theta\right)
]
[
y(\theta)=\frac{R}{3}\left(2\sin\theta+\sin2\theta\right)
]
Cette paramétrisation décrit une cardioïde, à une rotation/orientation près.
Autrement dit, la courbe n’est pas réellement dessinée dans le programme. Le programme ne trace que des segments. La cardioïde apparaît comme enveloppe de la famille de droites.
C’est précisément ce qui donne au projet son intérêt : une structure complexe devient visible à partir d’une règle extrêmement compacte.
Et lorsque n augmente ?
Avec peu de points, on distingue surtout les segments indépendants. Lorsque n devient grand, les droites échantillonnent de plus en plus finement la famille continue. Notre perception repère alors beaucoup plus facilement leur enveloppe.
Le GPU permet d’augmenter cette densité tout en conservant une interaction fluide.
4. La même idée, expliquée sans formules
Imaginons une horloge possédant non pas 12 positions, mais 200.
On numérote ces positions de 0 à 199.
On choisit ensuite une règle très simple : multiplier chaque numéro par 2 et revenir au début lorsque l’on dépasse 199.
Le point 17, par exemple, est relié au point 34. Le point 80 au point 160. Et si le calcul dépasse 199, le modulo le ramène à l’intérieur de notre cercle.
On répète l’opération pour tous les points.
Chaque liaison est parfaitement droite. Mais toutes ces droites ne sont pas réparties au hasard : leurs directions changent progressivement selon une règle commune. Elles viennent alors frôler une même frontière invisible.
Notre œil voit cette frontière avant même que le programme ne la dessine : c’est l’enveloppe.
C’est un peu comme observer des dizaines de tangentes autour d’un objet invisible. L’objet n’est jamais tracé directement, mais sa forme devient évidente grâce aux lignes qui l’effleurent.
Pourquoi le mouvement semble-t-il organique ?
Lorsque m varie lentement, chaque famille de lignes se transforme en la suivante.
Lorsque m varie vite, notre perception ne traite plus chaque état comme une figure complètement indépendante. Et si le moteur conserve volontairement une partie des états précédents, plusieurs géométries se superposent.
On peut modéliser ce principe de persistance par :
[
I_t=(1-\alpha)F_t+\alpha I_{t-1}
]
où :
F_test la nouvelle image calculée ;I_{t-1}est l’image persistante précédente ;αcontrôle la durée de la trace.
Avec α faible, les anciennes lignes disparaissent rapidement. Avec α élevé, les transformations laissent des traînées longues. C’est dans cette zone que des spirales, vagues et structures presque fluides deviennent particulièrement visibles.
Il n’y a donc pas de « courbe magique » ajoutée par-dessus : c’est l’accumulation temporelle d’une règle géométrique en évolution.
5. Quelques repères historiques
Math Art assemble des idées anciennes avec des outils très contemporains.
La cardioïde était étudiée bien avant l’informatique. Le nom est attribué au mathématicien Johann Castillon dans un travail publié en 1741. La courbe peut apparaître dans plusieurs constructions géométriques ; ici, elle émerge comme enveloppe de cordes associées par la multiplication sur le cercle.
L’arithmétique modulaire a été systématisée par Carl Friedrich Gauss dans les Disquisitiones Arithmeticae, publiées en 1801. Gauss y introduit notamment la notation moderne des congruences.
Deux siècles plus tard, un navigateur Web peut appliquer ces idées plusieurs dizaines de fois par seconde, les transformer en géométrie lumineuse et enregistrer leur évolution en vidéo.
Le changement n’est donc pas nécessairement dans la formule. Il est dans notre capacité à l’explorer de façon continue et interactive.
6. Pourquoi WebGL et Three.js ?
Une première version 2D suffit pour comprendre l’algorithme, mais elle devient vite limitée lorsque l’on veut :
- afficher plusieurs centaines ou milliers de segments ;
- recalculer la géométrie en temps réel ;
- appliquer une rotation de scène ;
- zoomer et déplacer la caméra ;
- utiliser des couleurs par sommet ;
- ajouter de la persistance ;
- conserver une fréquence d’affichage élevée.
La version actuelle repose sur Three.js et son moteur WebGL.
Les positions des segments sont stockées dans une BufferGeometry. Chaque paire de sommets forme un segment rendu par LineSegments. Cette approche est adaptée à une géométrie recalculée fréquemment et évite de créer un objet JavaScript distinct pour chaque ligne.
Schématiquement :
n, m, rayon
│
▼
calcul des angles
│
▼
positions des extrémités
│
▼
BufferGeometry
│
▼
LineSegments
│
▼
WebGLRenderer → GPU
La souris agit ensuite directement sur la caméra ou le groupe géométrique :
- glisser : rotation ;
- molette : zoom ;
- clic droit + glisser : déplacement ;
Shift+ molette : modification dem;- double-clic : recentrage.
Cette interaction transforme la figure en objet d’exploration, et non plus en simple illustration.
7. Capturer les formes en vidéo
L’export vidéo est devenu important après avoir observé que certaines transitions étaient plus intéressantes que les images fixes.
Le navigateur fournit directement les briques nécessaires :
const stream = canvas.captureStream(60);
const recorder = new MediaRecorder(stream);
captureStream() transforme le contenu vivant du canvas en MediaStream. MediaRecorder peut ensuite enregistrer ce flux et produire des blocs vidéo assemblés en fichier.
Dans Math Art, cela permet d’enregistrer :
- l’évolution automatique du multiplicateur ;
- la persistance ;
- les changements de paramètres ;
- les rotations et zooms effectués à la souris ;
- une séquence à 30 ou 60 images par seconde.
L’export devient alors une extension naturelle du laboratoire : observer, trouver une transformation intéressante, puis la conserver.
Une prochaine étape logique sera un mode Séquence capable de définir précisément :
m départ 2.000
m arrivée 7.000
durée 30 s
courbe linéaire / ease-in-out / sinusoïdale
rotation 0 → 180°
persistance 0.70 → 0.92
On passerait ainsi de l’enregistrement manuel à une véritable composition mathématique reproductible.
8. Du navigateur au VPS : le rôle du Homelab
Le projet reste volontairement léger côté serveur. Toute la génération géométrique est effectuée dans le navigateur de l’utilisateur.
Le conteneur n’a donc besoin que de servir des fichiers statiques :
FROM nginx:alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY . /usr/share/nginx/html
EXPOSE 80
Le stack Dockge rejoint le réseau Docker externe proxy :
services:
math-art:
build:
context: .
dockerfile: Dockerfile
container_name: math-art
restart: unless-stopped
networks:
- proxy
networks:
proxy:
external: true
Nginx Proxy Manager peut alors joindre directement :
Scheme: http
Forward Hostname: math-art
Forward Port: 80
Aucun port hôte supplémentaire n’est nécessaire pour l’accès public.

Accès privé par Tailscale
Pour le développement ou le diagnostic, un port peut être lié uniquement à l’adresse Tailscale du VPS :
ports:
- "<IP_TAILSCALE>:8003:80"
On obtient alors deux chemins indépendants :
PUBLIC
Internet → HTTPS → NPM → réseau proxy → math-art:80
PRIVÉ
Tailscale → :8003 → math-art:80
Cette séparation correspond à une règle que j’essaie de généraliser dans le Homelab : ne publier directement que ce qui doit réellement l’être.
9. Rebuild propre avec Dockge
Lorsqu’un stack contient un Dockerfile, un simple Start ne suffit pas toujours après une modification du frontend. L’ancienne image peut encore contenir les fichiers précédents.
Pour forcer une reconstruction complète :
cd /opt/homelab/stacks/math-art
docker compose down --remove-orphans
docker compose build --no-cache --pull
docker compose up -d --force-recreate
docker compose ps
docker compose logs --tail=50
On peut ensuite contrôler directement le contenu servi par Nginx :
docker exec math-art ls -lah /usr/share/nginx/html/
docker exec math-art wget -qO- http://127.0.0.1/ | head -n 20
Ce type de vérification est utile parce qu’il permet de séparer immédiatement trois catégories de problèmes :
- le build Docker ;
- le conteneur Nginx ;
- le reverse proxy ou le cache navigateur.
10. Une référence technique, mais aussi un outil de recherche
Math Art n’a pas vocation à rester une démonstration isolée.
Il s’inscrit dans un ensemble de projets où les mathématiques, la géométrie, les fractales, la musique et la perception peuvent être explorées avec des outils numériques.
Concerto à l’Infini part des nombres premiers pour produire une œuvre musicale, poétique et géométrique. Sa charte visuelle — noir profond, cyan, violet, magenta, lignes lumineuses fines et mouvements lents — fournit désormais un langage commun à cet écosystème.
Fractal Studio explore de son côté les équations itératives et leur mise en mouvement.
Math Art occupe une position différente : celle d’un laboratoire généraliste où une règle peut être manipulée pour observer ce qu’elle engendre.

Cette organisation permet aussi de donner deux lectures au même projet :
- dans le Homelab, il devient une référence technique documentant WebGL, Docker, Dockge, NPM, Tailscale et la démarche de développement ;
- dans un contexte de formation ou d’exploration, il peut servir à aborder les nombres, les formes, l’harmonie, les fractales, la perception et leurs relations.
La technologie devient alors un support de recherche plutôt qu’une finalité.
11. Prochaines expériences envisagées
La structure du laboratoire est pensée pour accueillir plusieurs expériences, par exemple :
Expérience 01 — Multiplication circulaire
Le moteur actuel : n, m, enveloppes, persistance et export vidéo.
Expérience 02 — Nombres premiers
Mettre en évidence les indices premiers, comparer les distributions et créer des transformations spécifiquement pilotées par les nombres premiers.
Expérience 03 — Fibonacci et nombre d’or
Explorer les angles, spirales et répartitions issues de la suite de Fibonacci et du nombre d’or.
Expérience 04 — Harmoniques
Relier rapports de fréquences, intervalles musicaux et représentations géométriques.
Expérience 05 — Fractales
Faire communiquer les transformations circulaires avec des systèmes itératifs et les outils de Fractal Studio.
Expérience 06 — Séquences génératives
Définir des scénarios de paramètres reproductibles et produire automatiquement des vidéos haute qualité.
L’objectif n’est donc pas de créer une collection de « beaux effets », mais une bibliothèque d’expériences documentées, chacune partant d’une règle identifiable.
Conclusion
Math Art résume assez bien ce que j’attends aujourd’hui de mon Homelab.
Le serveur n’est pas uniquement un endroit où faire tourner des conteneurs. Il devient un espace dans lequel une idée peut passer par plusieurs états :
question
↓
formule
↓
prototype
↓
interaction
↓
application
↓
conteneur
↓
déploiement
↓
documentation
↓
nouvelle recherche
Ici, tout est parti de segments tracés dans un cercle.
Ils ont fait apparaître une courbe. Puis une animation. Puis des formes mouvantes. Puis une application WebGL. Et finalement un nouveau laboratoire qui pourra accueillir d’autres relations entre nombres, géométrie, musique et fractales.
C’est probablement là que le projet devient le plus intéressant : la formule ne constitue pas la conclusion de l’expérience. Elle en est le point de départ.
Références
- Charte graphique — Concerto à l’Infini, Phase 1, version 1.0. Palette, typographies et principes d’interface utilisés comme base visuelle du laboratoire.
- MacTutor History of Mathematics, Cardioid — https://mathshistory.st-andrews.ac.uk/Curves/Cardioid/
- MacTutor History of Mathematics, Gauss: Disquisitiones Arithmeticae — https://mathshistory.st-andrews.ac.uk/Extras/Gauss_Disquisitiones/
- Three.js documentation,
BufferGeometry,LineSegments,WebGLRenderer— https://threejs.org/docs/ - MDN Web Docs,
HTMLCanvasElement.captureStream()— https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/captureStream - MDN Web Docs,
MediaRecorder— https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder
