import sqlite3 import db _CREATE_TABLE = """ CREATE TABLE _animation_clips ( id INTEGER PRIMARY KEY AUTOINCREMENT, screen_id INTEGER NOT NULL REFERENCES _screens(id) ON DELETE CASCADE, element_id INTEGER NOT NULL, kind TEXT NOT NULL DEFAULT 'animate_css', animate_name TEXT, custom_keyframes TEXT, start_time REAL NOT NULL DEFAULT 0, duration REAL NOT NULL DEFAULT 1, delay REAL NOT NULL DEFAULT 0, easing TEXT NOT NULL DEFAULT 'ease', iteration_count TEXT NOT NULL DEFAULT '1', created_at TEXT DEFAULT CURRENT_TIMESTAMP ); """ def ensure_animation_schema(slug: str) -> None: """Crée la table des clips d'animation si elle n'existe pas encore — même principe que ensure_flow_schema.py : un jeu créé avant l'ajout de cette fonctionnalité n'a pas besoin d'être migré à la main, la première ouverture du panneau timeline suffit. element_id désigne, selon game_type, un _screen_elements (éditeur document) OU un _scene_objects (éditeur jeu_2d) — animation-timeline.js est réutilisé TEL QUEL entre les deux éditeurs (voir le plan "Fondations d'une plateforme multi-éditeurs") et ne fait aucune distinction. Pas de contrainte FK vers _screen_elements : une scène jeu_2d n'a pas de ligne correspondante dans cette table, ce qui ferait échouer l'insertion avec PRAGMA foreign_keys=ON (voir db/connection.py). Le nettoyage à la suppression d'un élément/objet est fait manuellement (voir game_engine/elements/delete_element.py et game_engine/scenes/delete_scene_object.py), même patron que trigger_element_id/cond_element_a dans ensure_flow_schema.py.""" conn = db.connect(slug) cols = {r["name"]: r for r in conn.execute("PRAGMA table_info(_animation_clips)").fetchall()} if not cols: conn.executescript(_CREATE_TABLE) elif cols["element_id"]["notnull"] and _has_fk_on_element_id(conn): conn.executescript(_CREATE_TABLE.replace("CREATE TABLE _animation_clips", "CREATE TABLE _animation_clips_new")) conn.execute( """INSERT INTO _animation_clips_new (id, screen_id, element_id, kind, animate_name, custom_keyframes, start_time, duration, delay, easing, iteration_count, created_at) SELECT id, screen_id, element_id, kind, animate_name, custom_keyframes, start_time, duration, delay, easing, iteration_count, created_at FROM _animation_clips""" ) conn.execute("DROP TABLE _animation_clips") conn.execute("ALTER TABLE _animation_clips_new RENAME TO _animation_clips") conn.commit() conn.close() def _has_fk_on_element_id(conn: sqlite3.Connection) -> bool: return any( fk["from"] == "element_id" for fk in conn.execute("PRAGMA foreign_key_list(_animation_clips)").fetchall() )