import base64 import pathlib import textwrap root = pathlib.Path("/home/anthony/Documents/Projects/GameTime") anton = base64.b64encode((root / "assets/fonts/Anton-Regular.ttf").read_bytes()).decode() archivo = base64.b64encode((root / "assets/fonts/Archivo-Variable.ttf").read_bytes()).decode() # Palette Court Blazer (theme sombre) GOLD = "#C9A24A" CRIMSON = "#D72638" BG = "#080A12" SURFACE = "#141824" TEXT = "#F5F1E8" TEXT_SECONDARY = "#A7ADBA" BORDER = "#242A3A" TILE_W = 260 TILE_H = 330 FACE_D = 216 GAP = 24 N = 5 WIDTH = N * TILE_W + (N + 1) * GAP HEIGHT = TILE_H + 190 def watch_face(cx, cy, r, label_top, big_value, big_color, status_line, button_label, button_style, disconnected=False): parts = [] # bezel parts.append(f'') parts.append(f'') # crimson top accent arc (clin d\'oeil liseré 2px des cartes cles, adapte en arc sur le bezel interne) if not disconnected: parts.append(f'') else: parts.append(f'') top_y = cy - r * 0.44 value_y = cy - r * 0.02 status_y = cy + r * 0.30 btn_cy = cy + r * 0.62 btn_w = r * 1.5 btn_h = 40 label_color = TEXT_SECONDARY if not disconnected else "#5A6072" parts.append( f'{label_top}' ) parts.append( f'{big_value}' ) parts.append( f'{status_line}' ) # button pill bx = cx - btn_w / 2 by = btn_cy - btn_h / 2 if button_style == "gold_fill": fill, stroke, textcol = GOLD, GOLD, "#1A1206" elif button_style == "crimson_outline": fill, stroke, textcol = "none", CRIMSON, CRIMSON elif button_style == "crimson_fill": fill, stroke, textcol = CRIMSON, CRIMSON, TEXT else: # muted outline (disconnected) fill, stroke, textcol = "none", "#3A4152", TEXT_SECONDARY parts.append( f'' ) parts.append( f'{button_label}' ) return "\n".join(parts) states = [ dict( caption="1 — Pret a demarrer", sub="Etape / exercice sous chrono, pas encore lance", label_top="DRIBBLE COMBO", big_value="00:00", big_color=TEXT_SECONDARY, status_line="Serie 2 / 4", button_label="Demarrer", button_style="gold_fill", ), dict( caption="2 — Chrono en cours", sub="Le chrono actif tourne (exercice ou etape)", label_top="DRIBBLE COMBO", big_value="00:23", big_color=GOLD, status_line="Serie 2 / 4 - en cours", button_label="Arreter", button_style="crimson_outline", ), dict( caption="3 — Chrono en pause", sub="Chrono arrete avec valeur, reprise possible", label_top="DRIBBLE COMBO", big_value="00:23", big_color=GOLD, status_line="Serie 2 / 4 - en pause", button_label="Reprendre", button_style="gold_fill", ), dict( caption="4 — Pas de chrono actif", sub="Serie reps/score libre : l'action utile est de conclure", label_top="TIRS EN SUSPENSION", big_value="2 / 4", big_color=GOLD, status_line="Serie en cours", button_label="Terminer la serie", button_style="crimson_fill", ), dict( caption="5 — Montre non synchronisee", sub="Perte de liaison : dernier etat connu, sans alarmer", label_top="DERNIERE DONNEE RECUE", big_value="00:23", big_color="#5A6072", status_line="Non synchronisee", button_label="Reessayer", button_style="muted", disconnected=True, ), ] svg_parts = [ f'', '', f'', f'GAMETIME — MONTRE SYNCHRONISEE', f'Ecran unique, bouton contextuel unique — style Court Blazer', ] for i, st in enumerate(states): cx = GAP + TILE_W * i + TILE_W / 2 cy = 96 + FACE_D / 2 + 10 r = FACE_D / 2 svg_parts.append(watch_face(cx, cy, r, st["label_top"], st["big_value"], st["big_color"], st["status_line"], st["button_label"], st["button_style"], disconnected=st.get("disconnected", False))) cap_y = cy + r + 34 sub_y = cap_y + 22 svg_parts.append( f'{st["caption"]}' ) lines = textwrap.wrap(st["sub"], width=30) for li, line in enumerate(lines): svg_parts.append( f'{line}' ) svg_parts.append('') out = root / ".ideai/tickets/91/assets/watch_screen_mockup.svg" out.write_text("\n".join(svg_parts), encoding="utf-8") print("written", out, out.stat().st_size)