- Interface web (serveur_web.py, Flask, gabarits dans web/) : dépôt de GIF, PNG animés et séquences de PNG, aperçus animés, ordre de lecture, activer / désactiver, corbeille, « jouer maintenant » et « suivante ». Service systemd vitrine-web, activé par installer.sh. - Lecteur : réagit aux demandes de la page web (post-it dans /run/vitrine-pixels), écrit l'animation en cours, éteint la matrice proprement sur SIGTERM. - Matrice posée debout : réglage ROTATION (90 = image 8 × 32) dans matrice.py ; images couchées tournées automatiquement ; exemples, animations codées, aperçus et page web adaptés au format vertical. - Compatibilité Raspbian 11 Bullseye : partition /boot, Pillow 8.1, Flask 1.1. - Doc : nouveau guide INTERFACE_WEB.md ; README, GUIDE_KRITA, MODE_VITRINE, CODER_EN_PYTHON mis à jour (format 8 × 32, adresses Wi-Fi / câble du Pi). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
189 lines
6.6 KiB
Python
189 lines
6.6 KiB
Python
"""
|
|
=============================================================================
|
|
MES ANIMATIONS — dessiner avec du code (en Python)
|
|
Workshop « Vitrine pixels »
|
|
=============================================================================
|
|
|
|
Krita, c'est pour DESSINER les animations image par image.
|
|
Ce fichier, c'est pour les CALCULER : hasard, mouvements continus,
|
|
arc-en-ciel… des choses très longues à dessiner à la main.
|
|
|
|
Ce sont les mêmes animations que dans matrice_8x32.ino (Arduino),
|
|
traduites en Python : comparez les deux fichiers, ligne à ligne !
|
|
|
|
Lancer :
|
|
python3 mes_animations.py --simulateur (sur l'ordinateur)
|
|
sudo ~/vitrine-env/bin/python mes_animations.py (sur le Pi)
|
|
|
|
Transformer la playlist en GIF, pour que le lecteur la joue avec les
|
|
dessins de l'équipe Krita (la playlist est alors jouée une seule fois) :
|
|
python3 mes_animations.py --enregistrer animations/10_code.gif
|
|
|
|
|
|
PYTHON EN 6 RÈGLES (pour qui connaît l'Arduino)
|
|
-----------------------------------------------
|
|
1. Pas de point-virgule en fin de ligne, pas d'accolades { }.
|
|
2. Ce sont les ESPACES en début de ligne (l'indentation) qui disent ce
|
|
qui est « dans » une boucle ou une fonction. 4 espaces par niveau.
|
|
3. Pas de type à déclarer : x = 3 au lieu de int x = 3;
|
|
4. Une fonction : def nom(): au lieu de void nom() {
|
|
5. Une boucle : for x in range(32): (x va de 0 à 31)
|
|
au lieu de for (int x = 0; x < 32; x++) {
|
|
6. Un commentaire commence par # au lieu de //
|
|
|
|
|
|
LES OUTILS DE DESSIN (définis dans matrice.py)
|
|
----------------------------------------------
|
|
pixel(x, y, couleur) colore un pixel (x de 0 à 31, y de 0 à 7)
|
|
lire_pixel(x, y) renvoie la couleur d'un pixel
|
|
effacer() éteint tout (dans la toile)
|
|
effacer(couleur) remplit tout d'une couleur
|
|
assombrir(25) assombrit tout de 25 % (traînées)
|
|
montrer() AFFICHE la toile (sinon rien n'apparaît !)
|
|
attendre(100) attend 100 millisecondes
|
|
|
|
Couleurs : ROUGE, ORANGE, JAUNE, VERT, CYAN, BLEU, VIOLET, MAGENTA, ROSE,
|
|
BLANC, NOIR, ou (rouge, vert, bleu) de 0 à 255,
|
|
ou teinte(t) avec t de 0 à 255 pour faire le tour de l'arc-en-ciel.
|
|
"""
|
|
|
|
import random # pour le hasard
|
|
import sys # pour lire les options de la ligne de commande
|
|
|
|
# « from matrice import * » = importer TOUS les outils du moteur, pour
|
|
# écrire pixel(...) au lieu de matrice.pixel(...).
|
|
from matrice import *
|
|
|
|
|
|
# =============================================================================
|
|
# LES ANIMATIONS
|
|
# =============================================================================
|
|
# À VOUS DE JOUER : copiez une animation, renommez-la, modifiez-la,
|
|
# et ajoutez son nom dans la PLAYLIST tout en bas.
|
|
|
|
|
|
# --- Animation 1 : arc-en-ciel qui défile ---
|
|
def anim_arc_en_ciel():
|
|
for temps in range(256):
|
|
for x in range(LARGEUR):
|
|
for y in range(HAUTEUR):
|
|
# La teinte dépend de la position et du temps qui passe.
|
|
pixel(x, y, teinte((x + y) * 8 + temps * 2))
|
|
montrer()
|
|
attendre(20)
|
|
|
|
|
|
# --- Animation 2 : la pluie ---
|
|
def anim_pluie():
|
|
for image in range(200):
|
|
assombrir(25) # les gouttes laissent une traînée qui s'estompe
|
|
|
|
# Faire descendre toute l'image d'une ligne, en partant du bas
|
|
# (range(7, 0, -1) compte à rebours : 7, 6, 5… 1).
|
|
for y in range(HAUTEUR - 1, 0, -1):
|
|
for x in range(LARGEUR):
|
|
pixel(x, y, lire_pixel(x, y - 1))
|
|
|
|
# La ligne du haut s'éteint, puis 3 nouvelles gouttes au hasard.
|
|
for x in range(LARGEUR):
|
|
pixel(x, 0, NOIR)
|
|
for n in range(3):
|
|
pixel(random.randrange(LARGEUR), 0, (0, 120, 255))
|
|
|
|
montrer()
|
|
attendre(60)
|
|
|
|
|
|
# --- Animation 3 : un dessin en pixel art qui défile ---
|
|
# Une lettre par pixel, « . » = éteint. Toutes les lignes de même longueur,
|
|
# pas plus de 8 pixels de large ni de haut (le petit côté de la matrice).
|
|
DESSIN = [
|
|
".RR..RR.",
|
|
"RBBRRRRR",
|
|
"RBRRRRRR",
|
|
"RRRRRRRR",
|
|
".RRRRRR.",
|
|
"..RRRR..",
|
|
"...RR...",
|
|
]
|
|
|
|
# Un « dictionnaire » associe chaque lettre à une couleur.
|
|
COULEUR_DE_LETTRE = {
|
|
"R": ROUGE, "O": ORANGE, "J": JAUNE, "V": VERT, "C": CYAN,
|
|
"B": BLANC, "L": BLEU, "M": MAGENTA, "P": ROSE,
|
|
}
|
|
|
|
|
|
def dessiner_dessin(depart_x, depart_y):
|
|
for y, ligne in enumerate(DESSIN): # enumerate donne le numéro ET la ligne
|
|
for x, lettre in enumerate(ligne):
|
|
if lettre in COULEUR_DE_LETTRE:
|
|
pixel(depart_x + x, depart_y + y, COULEUR_DE_LETTRE[lettre])
|
|
|
|
|
|
def anim_dessin_qui_defile():
|
|
largeur_dessin = len(DESSIN[0]) # len = longueur de la ligne
|
|
hauteur_dessin = len(DESSIN) # = nombre de lignes
|
|
if HAUTEUR > LARGEUR:
|
|
# Matrice DEBOUT : le dessin monte du bas vers le haut.
|
|
x = (LARGEUR - largeur_dessin) // 2 # centré
|
|
for y in range(HAUTEUR, -hauteur_dessin - 1, -1):
|
|
effacer()
|
|
dessiner_dessin(x, y)
|
|
montrer()
|
|
attendre(70)
|
|
else:
|
|
# Matrice COUCHÉE : le dessin passe de droite à gauche.
|
|
y = (HAUTEUR - hauteur_dessin) // 2
|
|
for x in range(LARGEUR, -largeur_dessin - 1, -1):
|
|
effacer()
|
|
dessiner_dessin(x, y)
|
|
montrer()
|
|
attendre(70)
|
|
|
|
|
|
# --- Animation 4 : étincelles ---
|
|
def anim_etincelles():
|
|
for image in range(300):
|
|
assombrir(8)
|
|
pixel(random.randrange(LARGEUR), random.randrange(HAUTEUR),
|
|
teinte(random.randrange(256), saturation=200))
|
|
montrer()
|
|
attendre(15)
|
|
|
|
|
|
# --- Exemple : votre première animation ---
|
|
def anim_ma_premiere():
|
|
for x in range(LARGEUR):
|
|
effacer()
|
|
pixel(x, HAUTEUR // 2 - 1, JAUNE) # deux points au milieu de la hauteur
|
|
pixel(x, HAUTEUR // 2, JAUNE)
|
|
montrer()
|
|
attendre(50)
|
|
|
|
|
|
# =============================================================================
|
|
# LA PLAYLIST
|
|
# =============================================================================
|
|
# Mettez # devant une ligne pour sauter une animation.
|
|
|
|
def playlist():
|
|
anim_arc_en_ciel()
|
|
anim_pluie()
|
|
anim_dessin_qui_defile()
|
|
anim_etincelles()
|
|
# anim_ma_premiere()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
demarrer()
|
|
try:
|
|
while True: # en boucle, comme loop() sur l'Arduino
|
|
playlist()
|
|
if "--enregistrer" in sys.argv:
|
|
break # en enregistrement, un seul tour suffit
|
|
except KeyboardInterrupt:
|
|
print("\nArrêt demandé.")
|
|
finally:
|
|
eteindre()
|