diff --git a/8x32 PI/INTERFACE_WEB.md b/8x32 PI/INTERFACE_WEB.md
index 5b7ad1d..6dd0da8 100644
--- a/8x32 PI/INTERFACE_WEB.md
+++ b/8x32 PI/INTERFACE_WEB.md
@@ -36,6 +36,13 @@ Prenez celle du réseau sur lequel **vous** êtes :
| en **Wi-Fi** (téléphone, ordinateur portable) | **`http://172.16.50.27`** |
| par **câble** (ordinateur fixe de l'école) | `http://172.16.7.199` |
+> **Le plus simple : le QR code.** Le dossier [`qrcode/`](qrcode/) contient
+> le QR code de la page et une **affiche A5 à imprimer**
+> ([`affiche_interface_web.pdf`](qrcode/affiche_interface_web.pdf)) : on la
+> scanne avec l'appareil photo du téléphone, connecté au Wi-Fi de l'école.
+> Si l'adresse du Pi change, refaites-les :
+> `python3 outils/generer_qrcode.py http://NOUVELLE_ADRESSE`.
+
> **Pourquoi deux adresses ?** Une adresse, c'est comme l'adresse postale du
> Pi, mais **sur un réseau donné**. Le réseau Wi-Fi et le réseau filaire de
> l'école sont deux « villes » différentes, et l'école ne fait pas passer le
@@ -53,7 +60,10 @@ Prenez celle du réseau sur lequel **vous** êtes :
> marchent pas : la page n'est pas sur Internet, seulement sur le réseau local.
En haut de la page, en permanence : **ce que la matrice joue en ce moment**
-(mis à jour toutes les 2 secondes) et le bouton **Suivante ⏭**.
+(mis à jour toutes les 2 secondes), le bouton **Suivante ⏭** et le menu
+**Vitesse** : ×0,5 joue toutes les animations deux fois plus lentement, ×2
+deux fois plus vite. Le choix est gardé même après un redémarrage, et
+s'applique à partir de l'animation suivante.
---
diff --git a/8x32 PI/README.md b/8x32 PI/README.md
index d77dfe5..8161aa9 100644
--- a/8x32 PI/README.md
+++ b/8x32 PI/README.md
@@ -439,8 +439,10 @@ animation, pause entre deux, horaires) et de [`matrice.py`](matrice.py) :
| `LUMINOSITE` | matrice.py | `40` | de 0 à 255 ; montez en plein jour, en vitrine |
| `COURANT_MAX_MA` | matrice.py | `2500` | un peu **sous** la limite de l'alimentation |
| `ROTATION` | matrice.py | `90` | `90` = matrice debout (image 8 × 32), `0` = couchée (32 × 8) |
-| `INVERSER_X`, `INVERSER_Y` | matrice.py | `False` | sens de l'image (partie 8) |
+| `INVERSER_X`, `INVERSER_Y` | matrice.py | `True` | sens de l'image (partie 8) ; réglés sur la matrice de la vitrine |
+| `DECALAGE_X`, `DECALAGE_Y` | matrice.py | `1`, `0` | décale toute l'image d'un pixel (ici vers la droite : la colonne de gauche reste éteinte) |
| `GAMMA` | matrice.py | `2.2` | correction des couleurs (1.0 = aucune) |
+| `VITESSE` | lecteur.py | `1.0` | vitesse de lecture (0.5 = deux fois plus lent) ; le menu « Vitesse » de la page web a la priorité |
| `DUREE_MINIMUM` | lecteur.py | `10` | une animation courte est rejouée pendant au moins 10 s |
| `HORAIRES` | lecteur.py | `None` | ex. `("09:00", "22:30")` |
@@ -475,6 +477,7 @@ navigateur, et on gère la vitrine sans terminal ni carte SD.
| **Changer l'ordre** de lecture | ▲ ▼ (les fichiers sont renumérotés `01_`, `02_`…) |
| **Retirer** une animation de la boucle, sans la supprimer | ⏸ (elle passe dans « Pas jouées ») ; + pour la remettre |
| **Jouer tout de suite** une animation, ou **passer** à la suivante | ▶ et **Suivante ⏭** |
+| **Ralentir ou accélérer** toutes les animations | menu **Vitesse** en haut (×0,25 à ×2) |
| **Supprimer** | ✕ : elle va à la corbeille ; « Vider » efface pour de bon |
| **Savoir ce que joue la matrice** | en haut de la page, mis à jour toutes les 2 secondes |
@@ -490,7 +493,7 @@ réseau filaire de l'école ne communiquent pas entre eux : prenez celle de
| Vous êtes connecté… | Adresse |
|---|---|
-| en **Wi-Fi** (téléphone, portable) | **http://172.16.50.27** |
+| en **Wi-Fi** (téléphone, portable) | **http://172.16.50.27**, ou scannez le QR code du dossier [`qrcode/`](qrcode/) |
| par **câble** | http://172.16.7.199 |
Ces adresses sont distribuées par le réseau et **peuvent changer** : les
@@ -640,6 +643,7 @@ Pour voir ce que fait le lecteur quand il tourne tout seul (mode vitrine) :
| [`test_matrice.py`](test_matrice.py) | | test de branchement et d'orientation |
| [`mes_animations.py`](mes_animations.py) | | les animations de l'Arduino, traduites en Python |
| [`animations/`](animations/) | | exemples : GIF, séquence de PNG, APNG |
+| [`qrcode/`](qrcode/) | tous | QR code de la page web et affiche A5 à imprimer (refaits par `outils/generer_qrcode.py`) |
| [`schemas/`](schemas/) | | schémas de branchement, brochage de la puce, chaîne Krita → matrice, capture de l'interface web |
| `apercus/` | design | créé par `verifier_animation.py` : aperçus « façon LED » à partager |
| [`krita/palette_vitrine_pixels.gpl`](krita/palette_vitrine_pixels.gpl) | design | palette de couleurs adaptée aux LED, à importer dans Krita |
diff --git a/8x32 PI/lecteur.py b/8x32 PI/lecteur.py
index 03e2e53..998bf7f 100644
--- a/8x32 PI/lecteur.py
+++ b/8x32 PI/lecteur.py
@@ -91,6 +91,13 @@ IMAGES_PAR_SECONDE = 12
# Une image fixe reste affichée pendant cette durée.
DUREE_MINIMUM = 10
+# VITESSE de lecture de toutes les animations :
+# 1 = la vitesse prévue dans Krita ;
+# 0.5 = deux fois plus lent ; 2 = deux fois plus vite.
+# La page web peut la changer : elle l'écrit alors dans le fichier caché
+# « .vitesse.txt » du dossier des animations, qui a la priorité sur ce réglage.
+VITESSE = 1.0
+
# Noir entre deux animations, en secondes (0 = enchaîner directement).
PAUSE_ENTRE_ANIMATIONS = 0.3
@@ -256,8 +263,19 @@ def charger(chemin):
# 4. JOUER UNE ANIMATION
# =============================================================================
-def jouer(etapes, duree_minimum=DUREE_MINIMUM):
+def lire_vitesse_de_lecture(dossier):
+ """La vitesse choisie sur la page web (fichier .vitesse.txt), sinon VITESSE."""
+ try:
+ with open(os.path.join(dossier, ".vitesse.txt")) as f:
+ vitesse = float(f.read().strip().replace(",", "."))
+ return min(4.0, max(0.1, vitesse)) # entre ×0,1 et ×4, par prudence
+ except (OSError, ValueError):
+ return VITESSE
+
+
+def jouer(etapes, duree_minimum=DUREE_MINIMUM, vitesse=1.0):
"""Joue la liste d'étapes, et la rejoue jusqu'à atteindre la durée minimum.
+ vitesse = 0.5 : chaque image reste affichée deux fois plus longtemps.
S'arrête plus tôt si le serveur web demande autre chose (partie 5)."""
debut = time.monotonic()
while True:
@@ -265,7 +283,7 @@ def jouer(etapes, duree_minimum=DUREE_MINIMUM):
moment = time.monotonic()
matrice.montrer(image)
# On retire le temps déjà passé à afficher, pour garder le rythme.
- if not attendre_ou_interrompre(duree - (time.monotonic() - moment)):
+ if not attendre_ou_interrompre(duree / vitesse - (time.monotonic() - moment)):
return
if time.monotonic() - debut >= duree_minimum:
break
@@ -296,7 +314,7 @@ def jouer_animation(chemin, dossier):
print(f" ✗ impossible de lire ce fichier ({erreur}) : on passe au suivant")
return
if etapes:
- jouer(etapes)
+ jouer(etapes, vitesse=lire_vitesse_de_lecture(dossier))
if PAUSE_ENTRE_ANIMATIONS > 0:
matrice.effacer()
matrice.montrer()
diff --git a/8x32 PI/matrice.py b/8x32 PI/matrice.py
index ae1858e..216b8af 100644
--- a/8x32 PI/matrice.py
+++ b/8x32 PI/matrice.py
@@ -121,8 +121,16 @@ COURANT_MAX_MA = 2500
# - rouge et vert inversés (gauche/droite) → INVERSER_X = True
# - rouge et vert en bas au lieu d'en haut → INVERSER_Y = True
# - les deux à la fois (image à l'envers) → les deux à True
-INVERSER_X = False
-INVERSER_Y = False
+INVERSER_X = True
+INVERSER_Y = True
+
+# DÉCALAGE de l'image sur la matrice, en pixels (après INVERSER_X / Y).
+# DECALAGE_X = 1 : toute l'image glisse d'un pixel vers la DROITE ;
+# la colonne de gauche reste éteinte, la dernière colonne de l'image sort
+# de la matrice. Utile si un bord de la matrice est caché dans la vitrine.
+# (Valeurs négatives : vers la gauche ; DECALAGE_Y : vers le bas.)
+DECALAGE_X = 1
+DECALAGE_Y = 0
# CORRECTION GAMMA (voir partie 4). 2.2 = comme un écran d'ordinateur.
# 1.0 = pas de correction (les couleurs sombres paraîtront trop claires).
@@ -526,9 +534,18 @@ def assombrir(pourcentage):
for (r, v, b) in pixels_de(toile)])
+def decaler(image):
+ """Applique DECALAGE_X / DECALAGE_Y : l'image glisse, le vide est noir."""
+ if DECALAGE_X == 0 and DECALAGE_Y == 0:
+ return image
+ decalee = Image.new("RGB", (LARGEUR, HAUTEUR))
+ decalee.paste(image, (DECALAGE_X, DECALAGE_Y))
+ return decalee
+
+
def montrer(image=None):
- """Affiche la toile (ou une autre image de 32 × 8) sur l'écran."""
- _ecran.afficher(image if image is not None else toile)
+ """Affiche la toile (ou une autre image de la taille de la matrice) sur l'écran."""
+ _ecran.afficher(decaler(image if image is not None else toile))
def attendre(millisecondes):
diff --git a/8x32 PI/outils/generer_qrcode.py b/8x32 PI/outils/generer_qrcode.py
new file mode 100644
index 0000000..48ff639
--- /dev/null
+++ b/8x32 PI/outils/generer_qrcode.py
@@ -0,0 +1,328 @@
+#!/usr/bin/env python3
+"""
+=============================================================================
+ QR CODE ET AFFICHE D'ACCÈS À L'INTERFACE WEB
+ Workshop « Vitrine pixels »
+=============================================================================
+
+Fabrique, dans le dossier « qrcode » :
+ - qrcode_interface_web.png : le QR code seul (pour un message, un diaporama) ;
+ - qrcode_interface_web.svg : le même, en vectoriel (pour l'imprimer en grand) ;
+ - affiche_interface_web.svg : une affiche A5 à imprimer et à poser à côté
+ de la vitrine ou dans l'atelier, avec deux
+ compositions inspirées des animations de
+ l'équipe (qrcode/sources : « cascade », « tetris ») ;
+ - affiche_interface_web.pdf : la même, prête à imprimer (si rsvg-convert
+ est installé : paquet « librsvg2-bin »).
+
+On scanne le QR code avec l'appareil photo du téléphone : la page web de la
+vitrine s'ouvre. ⚠️ Le téléphone doit être connecté au Wi-Fi de l'école
+(la page n'est pas sur Internet).
+
+L'adresse du Pi peut changer (voir INTERFACE_WEB.md) : il suffit alors de
+relancer ce programme avec la nouvelle adresse :
+ python3 outils/generer_qrcode.py http://172.16.50.27
+
+Il faut le logiciel « qrencode » :
+ sudo apt install qrencode (Debian, Ubuntu, Raspberry Pi OS)
+ sudo pacman -S qrencode (Arch)
+ brew install qrencode (macOS)
+"""
+
+import os
+import shutil
+import subprocess
+import sys
+
+ICI = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+SORTIE = os.path.join(ICI, "qrcode")
+ADRESSE_PAR_DEFAUT = "http://172.16.50.27"
+
+
+def modules_du_qrcode(texte):
+ """Demande à qrencode le QR code en texte : une ligne par rangée,
+ « # » = case noire. Renvoie une liste de lignes de booléens."""
+ # -t ASCII : dessin en caractères (2 caractères par case) ; -m 0 : sans marge ;
+ # -l M : correction d'erreur moyenne (le code reste lisible s'il est un peu abîmé).
+ resultat = subprocess.run(["qrencode", "-t", "ASCII", "-m", "0", "-l", "M", texte],
+ capture_output=True, text=True, check=True)
+ lignes = [l for l in resultat.stdout.splitlines() if l.strip()]
+ return [[ligne[i] == "#" for i in range(0, len(ligne), 2)] for ligne in lignes]
+
+
+def cases_svg(modules, x0, y0, taille):
+ """Les cases noires du QR code, en rectangles SVG."""
+ return "".join(
+ f''
+ for y, ligne in enumerate(modules) for x, noir in enumerate(ligne) if noir)
+
+
+def qrcode_svg(modules, marge=4):
+ n = len(modules) + 2 * marge
+ return (f'\n')
+
+
+# =============================================================================
+# L'AFFICHE : deux compositions inspirées des animations de l'équipe
+# =============================================================================
+#
+# En haut, une coulée inspirée de « cascade » : un liquide bleu glacier qui
+# déborde du haut de la page, en strates séparées par de l'écume, avec des
+# stalactites qui gouttent. En bas, une partie de « tetris » : des pièces de
+# couleurs vives empilées sur toute la largeur, deux pièces encore en chute.
+#
+# Les deux compositions sont dessinées sur une grille de « LED » de 48 colonnes,
+# et leurs couleurs sont prises dans les fichiers de l'équipe (qrcode/sources).
+# Le hasard est « graine fixe » : on obtient la même affiche à chaque fois.
+
+import random
+
+SOURCES = os.path.join(SORTIE, "sources")
+COLONNES = 48 # largeur de la grille de pixels de l'affiche
+PAS = 148 / COLONNES # taille d'un pixel, en mm (≈ 3,1)
+REMPLISSAGE = 0.88 # un pixel = un carré un peu plus petit que le pas
+
+BLEUS_CASCADE = [(170, 199, 254), (119, 179, 254), (118, 218, 254)]
+COULEURS_TETRIS = [(255, 38, 38), (255, 127, 0), (255, 214, 0), (0, 214, 60),
+ (0, 220, 230), (255, 0, 255)]
+
+
+def couleurs_de(chemin, garder):
+ """Les couleurs d'une animation de l'équipe, triées par fréquence,
+ filtrées par la fonction « garder ». [] si le fichier est absent."""
+ try:
+ sys.path.insert(0, ICI)
+ import lecteur # noqa: E402
+ compte = {}
+ for image, _ in lecteur.charger(chemin):
+ for c in lecteur.matrice.pixels_de(image):
+ compte[c] = compte.get(c, 0) + 1
+ return [c for c, _ in sorted(compte.items(), key=lambda kv: -kv[1]) if garder(c)]
+ except Exception:
+ return []
+
+
+def hexa(c):
+ return f"#{c[0]:02x}{c[1]:02x}{c[2]:02x}"
+
+
+def pixel(x, y, couleur, y0=0.0):
+ """Un pixel de la grille de l'affiche, en colonne x, rangée y (depuis y0 mm)."""
+ marge = PAS * (1 - REMPLISSAGE) / 2
+ return (f'')
+
+
+def composition_cascade(bleus):
+ """Le liquide qui coule du haut de la page (sur fond blanc)."""
+ import math
+ hasard = random.Random(11)
+ clair, moyen, vif = (bleus + BLEUS_CASCADE)[:3]
+ cases = {}
+ # Profondeur du liquide dans chaque colonne : une ondulation lente.
+ profondeur = [int(5.2 + 1.6 * math.sin(x / 6.0) + 0.9 * math.sin(x / 2.7 + 2))
+ for x in range(COLONNES)]
+ for x in range(COLONNES):
+ for y in range(profondeur[x] + 1):
+ distance = profondeur[x] - y # distance au bord du liquide
+ # Deux traits d'écume blancs (des « trous ») qui suivent le bord,
+ # interrompus de temps en temps, comme dans l'animation.
+ if distance in (2, 5) and hasard.random() < 0.8:
+ continue
+ cases[(x, y)] = clair if distance <= 1 else moyen if distance <= 4 else vif
+ # Les coulures : des filets de 1 ou 2 pixels de large, terminés par une goutte.
+ x = hasard.randint(0, 2)
+ while x < COLONNES:
+ largeur = hasard.choice([1, 1, 2])
+ longueur = hasard.choice([1, 2, 2, 3, 4, 5])
+ haut = max(profondeur[min(x + i, COLONNES - 1)] for i in range(largeur)) + 1
+ for i in range(largeur):
+ for y in range(haut, haut + longueur):
+ cases[(x + i, y)] = clair
+ if longueur >= 3: # la goutte, plus large, en bas
+ for i in range(-1, largeur + 1):
+ cases[(x + i, haut + longueur)] = clair
+ for i in range(largeur):
+ cases[(x + i, haut + longueur + 1)] = clair
+ if hasard.random() < 0.35: # une goutte déjà détachée
+ cases[(x, haut + longueur + hasard.randint(3, 4))] = moyen
+ x += largeur + hasard.randint(2, 5)
+ return "".join(pixel(x, y, c) for (x, y), c in cases.items() if 0 <= x < COLONNES)
+
+
+PIECES = { # les 7 pièces de Tetris, (colonne, rangée) de chaque carré
+ "I": [(0, 0), (1, 0), (2, 0), (3, 0)], "O": [(0, 0), (1, 0), (0, 1), (1, 1)],
+ "T": [(0, 0), (1, 0), (2, 0), (1, 1)], "S": [(1, 0), (2, 0), (0, 1), (1, 1)],
+ "Z": [(0, 0), (1, 0), (1, 1), (2, 1)], "J": [(0, 0), (0, 1), (1, 1), (2, 1)],
+ "L": [(2, 0), (0, 1), (1, 1), (2, 1)],
+}
+
+
+def tourner(cases, fois):
+ for _ in range(fois):
+ cases = [(-y, x) for x, y in cases]
+ mx, my = min(x for x, _ in cases), min(y for _, y in cases)
+ return [(x - mx, y - my) for x, y in cases]
+
+
+def bloc(x, y, couleur, y0):
+ """Un carré de Tetris : la couleur, avec un petit reflet clair en haut à gauche."""
+ clair = tuple(int(c + (255 - c) * 0.55) for c in couleur)
+ marge = PAS * (1 - REMPLISSAGE) / 2
+ cote = PAS * REMPLISSAGE
+ gx, gy = x * PAS + marge, y0 + y * PAS + marge
+ return (f''
+ f'')
+
+
+def composition_tetris(couleurs, y_bas):
+ """Une partie de Tetris sur toute la largeur, le bas de la pile en y_bas (mm)."""
+ hasard = random.Random(5)
+ hauteur_max = 7
+ plateau = {} # (x, y) → couleur ; y = 0 en bas
+
+ def poser(forme, x0, y):
+ return [(x0 + x, y + dy) for x, dy in forme]
+
+ def atterrissage(forme, x0):
+ y = hauteur_max + 4
+ while y > 0 and all(c not in plateau for c in poser(forme, x0, y - 1)):
+ y -= 1
+ return y
+
+ for _ in range(400):
+ forme = tourner(PIECES[hasard.choice(list(PIECES))], hasard.randint(0, 3))
+ forme = [(x, max(y for _, y in forme) - y) for x, y in forme] # y vers le haut
+ largeur = max(x for x, _ in forme) + 1
+ essais = []
+ for x0 in range(COLONNES - largeur + 1):
+ y = atterrissage(forme, x0)
+ cases = poser(forme, x0, y)
+ # Les trous laissés sous la pièce (un bon joueur les évite).
+ trous = sum(1 for (cx, cy) in cases
+ if cy > 0 and (cx, cy - 1) not in plateau and (cx, cy - 1) not in cases)
+ essais.append((y + 3 * trous + hasard.random() * 1.5, x0, cases))
+ _, x0, cases = min(essais)
+ # L'horizon reste dentelé : plus haut au centre-gauche, plus bas ailleurs.
+ limite = hauteur_max - (2 if (x0 // 6) % 3 == 1 else 0)
+ if max(cy for _, cy in cases) >= limite:
+ continue
+ # Une couleur différente de celles des pièces qui la touchent.
+ voisines = {plateau[(cx + dx, cy + dy)] for cx, cy in cases
+ for dx, dy in ((1, 0), (-1, 0), (0, 1), (0, -1))
+ if (cx + dx, cy + dy) in plateau}
+ libres = [c for c in couleurs if c not in voisines] or couleurs
+ couleur = hasard.choice(libres)
+ for c in cases:
+ plateau[c] = couleur
+
+ morceaux = [bloc(x, -y - 1, c, y_bas) for (x, y), c in plateau.items()]
+ # Deux pièces encore en train de tomber, au-dessus de la pile.
+ sommet = max(y for _, y in plateau) + 1
+ for nom, x0, au_dessus, tour, couleur in (("T", 4, 3, 2, couleurs[0]),
+ ("L", 41, 4, 1, couleurs[-1])):
+ for x, y in tourner(PIECES[nom], tour):
+ morceaux.append(bloc(x0 + x, -(sommet + au_dessus) + y, couleur, y_bas))
+ return "".join(morceaux)
+
+
+def titre_en_pixels(texte, y0, taille, couleurs, depart=0):
+ """Écrit un texte avec la police 5 × 7 des exemples, centré,
+ une couleur par lettre (on fait le tour de la liste « couleurs »)."""
+ sys.path.insert(0, os.path.join(ICI, "outils"))
+ from generer_exemples import POLICE # noqa: E402
+ largeur = sum(len(POLICE[c][0]) + 1 for c in texte) - 1
+ x = (148 - largeur * taille) / 2
+ morceaux, n = [], depart
+ for c in texte:
+ couleur = hexa(couleurs[n % len(couleurs)])
+ if c != " ":
+ n += 1
+ for ligne, motif in enumerate(POLICE[c]):
+ for dx, p in enumerate(motif):
+ if p == "#":
+ morceaux.append(f'')
+ x += (len(POLICE[c][0]) + 1) * taille
+ return "".join(morceaux)
+
+
+def affiche_svg(modules, adresse):
+ """Affiche A5 (148 × 210 mm)."""
+ l, h = 148, 210
+ encre, gris = "#141414", "#6b665d"
+
+ bleus = couleurs_de(os.path.join(SOURCES, "cascade.gif"),
+ lambda c: c[2] > 200 and c[0] < 200) # les bleus
+ vives = couleurs_de(os.path.join(SOURCES, "tetris"),
+ lambda c: max(c) - min(c) > 180) # les saturées
+ # Une couleur par teinte (l'animation en contient des nuances très proches).
+ tetris = []
+ for c in vives + COULEURS_TETRIS:
+ if all(sum(abs(a - b) for a, b in zip(c, t)) > 120 for t in tetris):
+ tetris.append(c)
+
+ y_titre = 49
+ cote_qr = 56
+ x_qr, y_qr = (l - cote_qr) / 2, y_titre + 37
+ taille = cote_qr / len(modules)
+ y_texte = y_qr + cote_qr + 12
+ etapes = ["1. Connectez-vous au Wi-Fi de l'école.",
+ "2. Visez le QR code avec l'appareil photo.",
+ "3. Déposez vos animations, choisissez l'ordre."]
+ textes = (f''
+ f'{adresse.replace("http://", "")}'
+ + "".join(f'{e}'
+ for i, e in enumerate(etapes))
+ + f'Uniquement sur le Wi-Fi de l\'école (pas en 4G / 5G).')
+
+ return f"""
+"""
+
+
+def main():
+ adresse = sys.argv[1] if len(sys.argv) > 1 else ADRESSE_PAR_DEFAUT
+ if not adresse.startswith("http"):
+ adresse = "http://" + adresse
+ os.makedirs(SORTIE, exist_ok=True)
+
+ modules = modules_du_qrcode(adresse)
+ with open(os.path.join(SORTIE, "qrcode_interface_web.svg"), "w") as f:
+ f.write(qrcode_svg(modules))
+ with open(os.path.join(SORTIE, "affiche_interface_web.svg"), "w") as f:
+ f.write(affiche_svg(modules, adresse))
+ # Le PNG, directement par qrencode : 12 pixels par case, marge de 4 cases.
+ subprocess.run(["qrencode", "-o", os.path.join(SORTIE, "qrcode_interface_web.png"),
+ "-s", "12", "-m", "4", "-l", "M", adresse], check=True)
+ # Le PDF de l'affiche, si l'outil de conversion est là.
+ if shutil.which("rsvg-convert"):
+ subprocess.run(["rsvg-convert", "-f", "pdf",
+ "-o", os.path.join(SORTIE, "affiche_interface_web.pdf"),
+ os.path.join(SORTIE, "affiche_interface_web.svg")], check=True)
+ print(f"QR code pour {adresse} écrit dans {SORTIE}")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/8x32 PI/qrcode/affiche_interface_web.pdf b/8x32 PI/qrcode/affiche_interface_web.pdf
new file mode 100644
index 0000000..f0fa659
Binary files /dev/null and b/8x32 PI/qrcode/affiche_interface_web.pdf differ
diff --git a/8x32 PI/qrcode/affiche_interface_web.svg b/8x32 PI/qrcode/affiche_interface_web.svg
new file mode 100644
index 0000000..c6d39b8
--- /dev/null
+++ b/8x32 PI/qrcode/affiche_interface_web.svg
@@ -0,0 +1,12 @@
+
diff --git a/8x32 PI/qrcode/qrcode_interface_web.png b/8x32 PI/qrcode/qrcode_interface_web.png
new file mode 100644
index 0000000..b14636e
Binary files /dev/null and b/8x32 PI/qrcode/qrcode_interface_web.png differ
diff --git a/8x32 PI/qrcode/qrcode_interface_web.svg b/8x32 PI/qrcode/qrcode_interface_web.svg
new file mode 100644
index 0000000..980db8e
--- /dev/null
+++ b/8x32 PI/qrcode/qrcode_interface_web.svg
@@ -0,0 +1 @@
+
diff --git a/8x32 PI/qrcode/sources/cascade.gif b/8x32 PI/qrcode/sources/cascade.gif
new file mode 100644
index 0000000..d6ca39e
Binary files /dev/null and b/8x32 PI/qrcode/sources/cascade.gif differ
diff --git a/8x32 PI/qrcode/sources/tetris/images_par_seconde.txt b/8x32 PI/qrcode/sources/tetris/images_par_seconde.txt
new file mode 100644
index 0000000..f599e28
--- /dev/null
+++ b/8x32 PI/qrcode/sources/tetris/images_par_seconde.txt
@@ -0,0 +1 @@
+10
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0000.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0000.png
new file mode 100644
index 0000000..0ccfa64
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0000.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0001.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0001.png
new file mode 100644
index 0000000..efee28a
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0001.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0002.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0002.png
new file mode 100644
index 0000000..ecb7944
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0002.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0003.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0003.png
new file mode 100644
index 0000000..af5ce9d
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0003.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0004.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0004.png
new file mode 100644
index 0000000..e62df07
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0004.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0005.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0005.png
new file mode 100644
index 0000000..143b1d4
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0005.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0006.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0006.png
new file mode 100644
index 0000000..741e840
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0006.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0007.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0007.png
new file mode 100644
index 0000000..338042e
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0007.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0008.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0008.png
new file mode 100644
index 0000000..fbf7f38
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0008.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0009.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0009.png
new file mode 100644
index 0000000..399bf27
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0009.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0010.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0010.png
new file mode 100644
index 0000000..af22627
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0010.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0011.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0011.png
new file mode 100644
index 0000000..a62a588
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0011.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0012.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0012.png
new file mode 100644
index 0000000..7ba31ba
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0012.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0013.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0013.png
new file mode 100644
index 0000000..765cdd4
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0013.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0014.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0014.png
new file mode 100644
index 0000000..154c43c
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0014.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0015.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0015.png
new file mode 100644
index 0000000..2320c61
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0015.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0016.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0016.png
new file mode 100644
index 0000000..fa3cad3
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0016.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0017.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0017.png
new file mode 100644
index 0000000..7d2182b
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0017.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0018.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0018.png
new file mode 100644
index 0000000..99c8781
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0018.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0019.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0019.png
new file mode 100644
index 0000000..593d760
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0019.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0020.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0020.png
new file mode 100644
index 0000000..7126491
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0020.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0021.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0021.png
new file mode 100644
index 0000000..177b725
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0021.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0022.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0022.png
new file mode 100644
index 0000000..4ddefb6
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0022.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0023.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0023.png
new file mode 100644
index 0000000..a99521b
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0023.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0024.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0024.png
new file mode 100644
index 0000000..f7ad7bd
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0024.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0025.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0025.png
new file mode 100644
index 0000000..95ac753
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0025.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0026.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0026.png
new file mode 100644
index 0000000..6ef5789
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0026.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0027.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0027.png
new file mode 100644
index 0000000..81294fd
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0027.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0028.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0028.png
new file mode 100644
index 0000000..c57d813
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0028.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0029.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0029.png
new file mode 100644
index 0000000..ee32430
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0029.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0030.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0030.png
new file mode 100644
index 0000000..828d226
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0030.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0031.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0031.png
new file mode 100644
index 0000000..818bcab
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0031.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0032.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0032.png
new file mode 100644
index 0000000..a52b81d
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0032.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0033.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0033.png
new file mode 100644
index 0000000..1aa63c6
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0033.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0034.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0034.png
new file mode 100644
index 0000000..367ad6f
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0034.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0035.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0035.png
new file mode 100644
index 0000000..c4448c1
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0035.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0036.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0036.png
new file mode 100644
index 0000000..c4448c1
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0036.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0037.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0037.png
new file mode 100644
index 0000000..18bfa1d
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0037.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0038.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0038.png
new file mode 100644
index 0000000..2581982
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0038.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0039.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0039.png
new file mode 100644
index 0000000..b75b5c0
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0039.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0040.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0040.png
new file mode 100644
index 0000000..e250147
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0040.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0041.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0041.png
new file mode 100644
index 0000000..44fc601
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0041.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0042.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0042.png
new file mode 100644
index 0000000..02f0c52
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0042.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0043.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0043.png
new file mode 100644
index 0000000..c667586
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0043.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0044.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0044.png
new file mode 100644
index 0000000..387cbe1
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0044.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0045.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0045.png
new file mode 100644
index 0000000..387cbe1
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0045.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0046.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0046.png
new file mode 100644
index 0000000..debe80e
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0046.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0047.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0047.png
new file mode 100644
index 0000000..d47142b
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0047.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0048.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0048.png
new file mode 100644
index 0000000..d5560af
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0048.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0049.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0049.png
new file mode 100644
index 0000000..54a780b
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0049.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0050.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0050.png
new file mode 100644
index 0000000..cded2da
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0050.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0051.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0051.png
new file mode 100644
index 0000000..f375eec
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0051.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0052.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0052.png
new file mode 100644
index 0000000..67ead31
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0052.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0053.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0053.png
new file mode 100644
index 0000000..497b5fe
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0053.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0054.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0054.png
new file mode 100644
index 0000000..da538ec
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0054.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0055.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0055.png
new file mode 100644
index 0000000..dadf31a
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0055.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0056.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0056.png
new file mode 100644
index 0000000..d1ac7a1
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0056.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0057.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0057.png
new file mode 100644
index 0000000..fafb20e
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0057.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0058.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0058.png
new file mode 100644
index 0000000..aaf62e9
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0058.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0059.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0059.png
new file mode 100644
index 0000000..ec3c717
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0059.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0060.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0060.png
new file mode 100644
index 0000000..0b1a8c7
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0060.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0061.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0061.png
new file mode 100644
index 0000000..773cc60
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0061.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0062.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0062.png
new file mode 100644
index 0000000..773cc60
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0062.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0063.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0063.png
new file mode 100644
index 0000000..773cc60
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0063.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0064.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0064.png
new file mode 100644
index 0000000..4560c1c
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0064.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0065.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0065.png
new file mode 100644
index 0000000..8f79ca0
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0065.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0066.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0066.png
new file mode 100644
index 0000000..ab75a77
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0066.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0067.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0067.png
new file mode 100644
index 0000000..46611d9
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0067.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0068.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0068.png
new file mode 100644
index 0000000..5d9b874
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0068.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0069.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0069.png
new file mode 100644
index 0000000..c9d13df
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0069.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0070.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0070.png
new file mode 100644
index 0000000..5e777cb
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0070.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0071.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0071.png
new file mode 100644
index 0000000..34f243c
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0071.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0072.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0072.png
new file mode 100644
index 0000000..d5f686d
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0072.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0073.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0073.png
new file mode 100644
index 0000000..b04a0c3
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0073.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0074.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0074.png
new file mode 100644
index 0000000..962e119
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0074.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0075.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0075.png
new file mode 100644
index 0000000..d400d2a
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0075.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0076.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0076.png
new file mode 100644
index 0000000..d8640d5
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0076.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0077.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0077.png
new file mode 100644
index 0000000..2be17c2
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0077.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0078.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0078.png
new file mode 100644
index 0000000..e6d6857
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0078.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0079.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0079.png
new file mode 100644
index 0000000..31f2c81
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0079.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0080.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0080.png
new file mode 100644
index 0000000..31f2c81
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0080.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0081.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0081.png
new file mode 100644
index 0000000..19cde57
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0081.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0082.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0082.png
new file mode 100644
index 0000000..b8be795
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0082.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0083.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0083.png
new file mode 100644
index 0000000..b59374d
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0083.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0084.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0084.png
new file mode 100644
index 0000000..0416a64
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0084.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0085.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0085.png
new file mode 100644
index 0000000..3a3a1b5
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0085.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0086.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0086.png
new file mode 100644
index 0000000..8e78eec
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0086.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0087.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0087.png
new file mode 100644
index 0000000..1eb9ac4
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0087.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0088.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0088.png
new file mode 100644
index 0000000..c4fd968
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0088.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0089.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0089.png
new file mode 100644
index 0000000..419078e
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0089.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0090.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0090.png
new file mode 100644
index 0000000..2e5a5a1
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0090.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0091.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0091.png
new file mode 100644
index 0000000..2df2951
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0091.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0092.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0092.png
new file mode 100644
index 0000000..7c0b5fd
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0092.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0093.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0093.png
new file mode 100644
index 0000000..112ad89
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0093.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0094.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0094.png
new file mode 100644
index 0000000..773aa32
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0094.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0095.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0095.png
new file mode 100644
index 0000000..f9fdb19
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0095.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0096.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0096.png
new file mode 100644
index 0000000..24e1347
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0096.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0097.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0097.png
new file mode 100644
index 0000000..4cd8ad4
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0097.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0098.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0098.png
new file mode 100644
index 0000000..69288cf
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0098.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0099.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0099.png
new file mode 100644
index 0000000..1aea368
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0099.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0100.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0100.png
new file mode 100644
index 0000000..1aea368
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0100.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0101.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0101.png
new file mode 100644
index 0000000..24f7b7a
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0101.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0102.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0102.png
new file mode 100644
index 0000000..c006968
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0102.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0103.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0103.png
new file mode 100644
index 0000000..298aff8
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0103.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0104.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0104.png
new file mode 100644
index 0000000..49f2987
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0104.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0105.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0105.png
new file mode 100644
index 0000000..3195d32
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0105.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0106.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0106.png
new file mode 100644
index 0000000..ce67bb4
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0106.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0107.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0107.png
new file mode 100644
index 0000000..00407e5
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0107.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0108.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0108.png
new file mode 100644
index 0000000..02765b2
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0108.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0109.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0109.png
new file mode 100644
index 0000000..6726d7e
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0109.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0110.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0110.png
new file mode 100644
index 0000000..a9c54be
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0110.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0111.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0111.png
new file mode 100644
index 0000000..a043ba2
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0111.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0112.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0112.png
new file mode 100644
index 0000000..dc7e909
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0112.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0113.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0113.png
new file mode 100644
index 0000000..1707042
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0113.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0114.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0114.png
new file mode 100644
index 0000000..d766732
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0114.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0115.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0115.png
new file mode 100644
index 0000000..fef3f46
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0115.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0116.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0116.png
new file mode 100644
index 0000000..8fc5081
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0116.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0117.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0117.png
new file mode 100644
index 0000000..4562731
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0117.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0118.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0118.png
new file mode 100644
index 0000000..62ad5e9
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0118.png differ
diff --git a/8x32 PI/qrcode/sources/tetris/tetris_final_0119.png b/8x32 PI/qrcode/sources/tetris/tetris_final_0119.png
new file mode 100644
index 0000000..263c6c5
Binary files /dev/null and b/8x32 PI/qrcode/sources/tetris/tetris_final_0119.png differ
diff --git a/8x32 PI/serveur_web.py b/8x32 PI/serveur_web.py
index 23a3b70..b615ab0 100644
--- a/8x32 PI/serveur_web.py
+++ b/8x32 PI/serveur_web.py
@@ -350,6 +350,9 @@ def accueil():
actives=[fiche(n) for n in actives()],
desactivees=[fiche(n, DESACTIVEES) for n in desactivees()],
en_cours=lire_en_cours(),
+ vitesse=lecteur.lire_vitesse_de_lecture(DOSSIER),
+ vitesses=[(0.25, "×0,25 (très lent)"), (0.5, "×0,5 (lent)"), (0.75, "×0,75"),
+ (1.0, "×1 (normal)"), (1.5, "×1,5"), (2.0, "×2 (rapide)")],
nb_corbeille=nb_corbeille,
dossier=DOSSIER,
adresses=adresses_du_pi(),
@@ -507,6 +510,18 @@ def action():
ranger_dans(CORBEILLE, nom, depuis=os.path.join(DOSSIER, DESACTIVEES))
flash(f"« {nom} » est dans la corbeille.", "ok")
+ elif quoi == "vitesse":
+ try:
+ vitesse = float(request.form.get("vitesse", "1"))
+ assert 0.1 <= vitesse <= 4
+ except (ValueError, AssertionError):
+ abort(400)
+ # Un petit fichier caché dans le dossier des animations : il est lu par
+ # le lecteur au début de chaque animation, et survit aux redémarrages.
+ with open(os.path.join(DOSSIER, ".vitesse.txt"), "w") as f:
+ f.write(f"{vitesse:g}\n")
+ flash(f"Vitesse de lecture : ×{vitesse:g} (à partir de la prochaine animation).", "ok")
+
elif quoi == "vider_corbeille":
shutil.rmtree(os.path.join(DOSSIER, CORBEILLE), ignore_errors=True)
flash("Corbeille vidée.", "ok")
diff --git a/8x32 PI/web/page.html b/8x32 PI/web/page.html
index 0b1a1e8..a700bd7 100644
--- a/8x32 PI/web/page.html
+++ b/8x32 PI/web/page.html
@@ -22,6 +22,18 @@
+ {# Vitesse : le formulaire s'envoie tout seul dès qu'on change la valeur. #}
+
diff --git a/8x32 PI/web/style.css b/8x32 PI/web/style.css
index d9e913a..92e46db 100644
--- a/8x32 PI/web/style.css
+++ b/8x32 PI/web/style.css
@@ -61,6 +61,11 @@ h1 { margin: 0; font-size: 1.3rem; display: flex; align-items: center; gap: 10px
}
.statut { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.statut form { margin: 0; }
+.vitesse label { display: flex; align-items: center; gap: 6px; }
+.vitesse select {
+ font: inherit; padding: 6px 8px; border-radius: 8px;
+ background: #2a2826; color: #f1ede6; border: 1px solid #3d3935;
+}
.pastille {
width: 10px; height: 10px; border-radius: 50%;
background: #4cc283; box-shadow: 0 0 8px #4cc283;
diff --git a/CLAUDE.md b/CLAUDE.md
index 565134a..831af29 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -80,7 +80,7 @@ Le projet avance en deux temps :
- Matériel : Pi 3B+ / 4 / Zero 2 W (pas le Pi 5 : `rpi_ws281x` ne le gère pas), GPIO 18 (patte 12) → **74AHCT125** (3,3 V → 5 V, VCC pris sur le fil rouge de la fiche DIN) → 330 Ω → DIN. Audio désactivé (`dtparam=audio=off`).
- Installation : `installation/installer.sh` (venv `~/vitrine-env`, services systemd `vitrine-pixels` (lecteur) et `vitrine-web` (interface)). Docs : README, INSTALLATION_PI, GUIDE_KRITA, MODE_VITRINE (overlay FS), INTERFACE_WEB, CODER_EN_PYTHON.
- Interface web `serveur_web.py` (Flask, port 80, gabarits dans `web/`) : dépôt GIF/PNG/séquences, ordre (renommage `01_…`), activer/désactiver (`.desactivees/`), corbeille (`.corbeille/`), « jouer maintenant » via post-it `/run/vitrine-pixels/demande` lu par le lecteur.
-- Pi installé : Raspberry Pi 3 Model B, Raspbian 11 Bullseye 32 bits (dossier boot = `/boot`, Pillow 8.1, Flask 1.1), Ethernet débranché : accès uniquement en Wi-Fi, `ssh devel@172.16.50.27` (clé ESADHaR) ; l'ancienne adresse câble était 172.16.7.199. Le Wi-Fi et le filaire de l'école ne se voient pas : depuis le Wi-Fi, page web sur http://172.16.50.27 (adresses DHCP, affichées en bas de la page). Matrice posée debout : `ROTATION = 90`, image 8 × 32. Pas de 74AHCT125 pendant le workshop : **montage A** (GPIO 18 → 330 Ω → DIN, matrice en 4,4 V) testé et validé ; montage B (transistor 2N3904 inverseur) essayé : échec, trop lent (temps de stockage ≈ 0,2 µs face à un « 0 » de 0,4 µs), seule la 1re LED s'allume au hasard. Lecteur `vitrine-pixels` activé au démarrage le 2026-10-08.
+- Pi installé : Raspberry Pi 3 Model B, Raspbian 11 Bullseye 32 bits (dossier boot = `/boot`, Pillow 8.1, Flask 1.1), Ethernet débranché : accès uniquement en Wi-Fi, `ssh devel@172.16.50.27` (clé ESADHaR) ; l'ancienne adresse câble était 172.16.7.199. Le Wi-Fi et le filaire de l'école ne se voient pas : depuis le Wi-Fi, page web sur http://172.16.50.27 (adresses DHCP, affichées en bas de la page). Matrice posée debout : `ROTATION = 90`, image 8 × 32 ; sur la vitrine `INVERSER_X = INVERSER_Y = True` (demi-tour) et `DECALAGE_X = 1` (image décalée d'un pixel vers la droite). Vitesse de lecture réglable depuis la page web (`.vitesse.txt`, ×0,5 actuellement). QR code et affiche A5 : `outils/generer_qrcode.py` → `qrcode/`. Pas de 74AHCT125 pendant le workshop : **montage A** (GPIO 18 → 330 Ω → DIN, matrice en 4,4 V) testé et validé ; montage B (transistor 2N3904 inverseur) essayé : échec, trop lent (temps de stockage ≈ 0,2 µs face à un « 0 » de 0,4 µs), seule la 1re LED s'allume au hasard. Lecteur `vitrine-pixels` activé au démarrage le 2026-10-08.
- Schémas générés par `outils/schemas.py`, exemples et palette Krita par `outils/generer_exemples.py`.
### Chiffres clés