# Preset manim-diagram — technical flow diagram that builds itself (Manim CE, light theme, Geist). # Usage (run INSIDE the deliverable folder, never in root — a stray struct.py there breaks Python): # manim -qh --fps 30 -r 1920,1080 --disable_caching scene.py SkillFlow # → media/videos/scene/1080p30/SkillFlow.mp4 # manim -ql ... for a fast preview. Edit the NODES/EDGES/TEXT block below to reuse it. from manim import * FONT = "Geist" MONO = "Geist Mono" INK = "#1a1a1a" MUTED = "#6e6e73" ACCENT = "#0071e3" CARD = "#ffffff" config.background_color = "#f5f5f7" TITLE = "Cómo carga Claude un skill" SUB = "Solo lee lo que tu pedido necesita" # (key, label, sublabel, (x, y)) — frame is ±7.1 × ±4 units; keep card edges inside ±6.3 (96 px title-safe) NODES = [ ("ask", "Tu pedido", "«haz un reel de 15 s»", (-5.0, 0.3)), ("desc", "description", "siempre en contexto", (-1.85, 0.3)), ("skill", "SKILL.md", "se carga si encaja", (1.3, 0.3)), ("refs", "references/", "bajo demanda", (4.75, 1.75)), ("scripts", "scripts/", "se ejecutan", (4.75, -1.15)), ] EDGES = [("ask", "desc"), ("desc", "skill"), ("skill", "refs"), ("skill", "scripts")] FOOT = "Menos contexto · mejores resultados" def card(label, sub, accent=False): box = RoundedRectangle(corner_radius=0.22, width=2.5, height=1.25, stroke_width=2, stroke_color=ACCENT if accent else "#d2d2d7", fill_color=CARD, fill_opacity=1) t1 = Text(label, font=MONO if "/" in label or "." in label else FONT, weight=MEDIUM, color=INK).scale(0.46) t2 = Text(sub, font=FONT, color=MUTED).scale(0.31) VGroup(t1, t2).arrange(DOWN, buff=0.14).move_to(box) shadow = box.copy().set_fill("#000000", opacity=0.06).set_stroke(width=0).shift(DOWN * 0.07 + RIGHT * 0.03) return VGroup(shadow, box, t1, t2) class SkillFlow(Scene): def construct(self): title = Text(TITLE, font=FONT, weight=SEMIBOLD, color=INK).scale(0.78).to_edge(UP, buff=0.75).to_edge(LEFT, buff=0.9) sub = Text(SUB, font=FONT, color=MUTED).scale(0.42).next_to(title, DOWN, aligned_edge=LEFT, buff=0.22) self.play(FadeIn(title, shift=UP * 0.2), run_time=0.8) self.play(FadeIn(sub, shift=UP * 0.15), run_time=0.6) cards = {k: card(l, s, accent=(k == "skill")).move_to([x, y - 0.6, 0]) for k, l, s, (x, y) in NODES} arrows = {} for a, b in EDGES: arrows[(a, b)] = Arrow(cards[a][1].get_right(), cards[b][1].get_left(), buff=0.12, stroke_width=4, color="#a1a1a6", tip_length=0.2, max_tip_length_to_length_ratio=0.4) self.play(FadeIn(cards["ask"], shift=RIGHT * 0.3), run_time=0.6) for a, b in EDGES: self.play(GrowArrow(arrows[(a, b)]), run_time=0.45) self.play(FadeIn(cards[b], shift=RIGHT * 0.3), run_time=0.5) # a pulse travels the path: request → description → SKILL.md → both branches for a, b in EDGES[:2]: dot = Dot(color=ACCENT, radius=0.09).move_to(arrows[(a, b)].get_start()) self.play(MoveAlongPath(dot, Line(arrows[(a, b)].get_start(), arrows[(a, b)].get_end())), run_time=0.45, rate_func=smooth) self.remove(dot) self.play(Indicate(cards["skill"][1], color=ACCENT, scale_factor=1.06), run_time=0.6) dots = [Dot(color=ACCENT, radius=0.09).move_to(arrows[e].get_start()) for e in EDGES[2:]] self.play(*[MoveAlongPath(d, Line(arrows[e].get_start(), arrows[e].get_end())) for d, e in zip(dots, EDGES[2:])], run_time=0.5) self.remove(*dots) for k in ("refs", "scripts"): cards[k][1].set_stroke(ACCENT) self.play(*[Indicate(cards[k][1], color=ACCENT, scale_factor=1.05) for k in ("refs", "scripts")], run_time=0.6) foot = Text(FOOT, font=MONO, color=MUTED).scale(0.34).to_edge(DOWN, buff=0.7) self.play(FadeIn(foot, shift=UP * 0.1), run_time=0.6) self.wait(1.4)