From 59355909f2de9236af8168a26c70bcf6caa3b285 Mon Sep 17 00:00:00 2001 From: Elvis Claros Castro Date: Sat, 26 Sep 2026 20:21:47 -0300 Subject: Import video pipeline as it was --- scenes/v11_collatz.py | 171 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 scenes/v11_collatz.py (limited to 'scenes/v11_collatz.py') diff --git a/scenes/v11_collatz.py b/scenes/v11_collatz.py new file mode 100644 index 0000000..49436b8 --- /dev/null +++ b/scenes/v11_collatz.py @@ -0,0 +1,171 @@ +# -*- coding: utf-8 -*- +import sys, os, math +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from manim import * +from tiktok import * + +X0, X1 = -3.75, 3.75 +Y0, Y1 = -1.30, 3.30 + + +def seq(n): + s = [n] + while n != 1: + n = n // 2 if n % 2 == 0 else 3 * n + 1 + s.append(n) + return s + + +def curva(sq, color=AMBAR, sw=5, mx=None, nx=None, log=False): + """Trayectoria como poligonal. mx/nx permiten compartir escala entre curvas.""" + mx = mx or max(sq) + nx = nx or len(sq) + if log: + f = lambda v: math.log(v) / math.log(mx) + else: + f = lambda v: v / mx + pts = [[X0 + (X1 - X0) * i / (nx - 1), Y0 + (Y1 - Y0) * f(sq[i]), 0] + for i in range(len(sq))] + m = VMobject(stroke_color=color, stroke_width=sw) + m.set_points_as_corners(pts) + return m, pts + + +def tile(v, col): + t = Text(str(v), font=FONT, font_size=44, weight=BOLD, color="#0B0F1A") + box = RoundedRectangle(corner_radius=0.16, width=max(0.95, t.width + 0.45), + height=0.88, stroke_width=0, fill_color=col, fill_opacity=1) + return VGroup(box, t) + + +class Collatz(TikTok): + NAME = "collatz" + + def construct(self): + self.prepare() + chip = self.chip("Abierto desde 1937", ROSA) + + with self.beat(0) as b: + n = self.big("27", 150, AMBAR).move_to(UP * 1.9) + cap = self.fit(Text("agarrá cualquier número", font=FONT, font_size=50, + weight=BOLD, color=WHITE), 8.2).move_to(DOWN * 0.3) + b.play(FadeIn(chip, shift=DOWN * 0.3), run_time=0.45) + b.play(FadeIn(n, scale=0.6), run_time=0.45) + for v in ("6", "19", "41"): + b.play(Transform(n, self.big(v, 150, AMBAR).move_to(UP * 1.9)), run_time=0.26) + b.play(FadeIn(cap, shift=UP * 0.15), run_time=0.5) + + def regla(txt, op, col): + a = Text(txt, font=FONT, font_size=46, weight=BOLD, color=col) + fl = Arrow(ORIGIN, RIGHT * 0.85, buff=0, color=GRIS, stroke_width=6, + max_tip_length_to_length_ratio=0.35) + c = Text(op, font=FONT, font_size=52, weight=BOLD, color=WHITE) + return VGroup(a, fl, c).arrange(RIGHT, buff=0.35) + + with self.beat(1) as b: + b.play(FadeOut(VGroup(n, cap)), run_time=0.3) + r1 = regla("es PAR", "÷ 2", CELESTE) + r2 = regla("es IMPAR", "× 3 + 1", AMBAR) + rr = VGroup(r1, r2).arrange(DOWN, buff=0.7).move_to(UP * 1.6) + self.fit(rr, 8.2) + b.play(FadeIn(r1, shift=UP * 0.2), run_time=0.7) + b.play(FadeIn(r2, shift=UP * 0.2), run_time=0.7) + + s6 = seq(6) + with self.beat(2) as b: + b.play(rr.animate.scale(0.72).move_to(UP * 5.2), run_time=0.5) + seis = self.big("6", 140, VERDE).move_to(UP * 1.0) + b.play(FadeIn(seis, scale=0.6), run_time=0.6) + + with self.beat(3) as b: + b.play(FadeOut(seis), run_time=0.25) + tiles = VGroup(*[tile(v, VERDE if v == 1 else (CELESTE if v % 2 == 0 else AMBAR)) + for v in s6]) + fila1 = VGroup(*tiles[:5]).arrange(RIGHT, buff=0.28) + fila2 = VGroup(*tiles[5:]).arrange(RIGHT, buff=0.28) + grid = VGroup(fila1, fila2).arrange(DOWN, buff=0.45).move_to(UP * 1.4) + self.fit(grid, 8.2) + b.play(LaggedStart(*[FadeIn(t, scale=0.6) for t in tiles], + lag_ratio=0.5), run_time=max(1.4, b.floor - 0.4)) + + with self.beat(4) as b: + b.play(Circumscribe(tiles[-1], color=VERDE, buff=0.12, stroke_width=6), + run_time=0.7) + b.play(FadeOut(grid), run_time=0.35) + siete = self.big("7", 140, AMBAR).move_to(UP * 1.0) + b.play(FadeIn(siete, scale=0.6), run_time=0.5) + + base = Line([X0 - 0.25, Y0, 0], [X1 + 0.25, Y0, 0], stroke_width=4, color="#33405C") + uno = Text("1", font=FONT, font_size=32, weight=BOLD, color=VERDE) + uno.next_to(base.get_start(), LEFT, buff=0.12) + + s7 = seq(7) + with self.beat(5) as b: + b.play(FadeOut(siete), run_time=0.25) + c7, p7 = curva(s7, AMBAR, 6) + pico = Text("52", font=FONT, font_size=34, weight=BOLD, color=AMBAR) + pico.next_to([p7[s7.index(max(s7))][0], Y1, 0], UP, buff=0.12) + b.play(FadeIn(base), FadeIn(uno), run_time=0.35) + b.play(Create(c7), run_time=max(1.2, b.floor - 1.1)) + b.play(FadeIn(pico), run_time=0.4) + + s27 = seq(27) + with self.beat(6) as b: + b.play(FadeOut(VGroup(c7, pico)), run_time=0.3) + c27, p27 = curva(s27, ROSA, 5) + k = s27.index(max(s27)) + top = Text("9.232", font=FONT, font_size=40, weight=BOLD, color=ROSA) + top.next_to([p27[k][0], Y1, 0], UP, buff=0.12) + lab = Text("27", font=FONT, font_size=40, weight=BOLD, color=ROSA) + lab.move_to([X0 - 0.05, Y1 + 0.45, 0]) + b.play(FadeIn(lab), run_time=0.3) + b.play(Create(c27), run_time=max(1.3, b.floor - 1.0)) + b.play(FadeIn(top), run_time=0.4) + + with self.beat(7) as b: + fin = Dot([p27[-1][0], Y0, 0], radius=0.14, color=VERDE) + pasos = self.fit(Text("111 pasos y cae al 1", font=FONT, font_size=48, + weight=BOLD, color=VERDE), 8.0).move_to(DOWN * 2.6) + b.play(FadeIn(fin, scale=0.4), run_time=0.4) + b.play(Flash(fin, color=VERDE, line_length=0.35, num_lines=14, + flash_radius=0.8), run_time=0.6) + b.play(FadeIn(pasos, shift=UP * 0.15), run_time=0.6) + + with self.beat(8) as b: + b.play(FadeOut(VGroup(c27, top, lab, fin, pasos)), run_time=0.4) + todos = [seq(k) for k in range(2, 80)] + MX = max(max(s) for s in todos) + NX = max(len(s) for s in todos) + cols = [AMBAR, CELESTE, ROSA, VERDE] + gr = VGroup(*[curva(s, cols[i % 4], 2.4, mx=MX, nx=NX, log=True)[0] + for i, s in enumerate(todos)]) + gr.set_stroke(opacity=0.65) + b.play(LaggedStart(*[Create(c) for c in gr], lag_ratio=0.02), + run_time=max(1.6, b.floor - 0.9)) + marca = self.fit(Text("todos terminan en 1", font=FONT, font_size=46, + weight=BOLD, color=VERDE), 8.0).move_to(DOWN * 2.6) + b.play(FadeIn(marca, shift=UP * 0.15), run_time=0.6) + + with self.beat(9) as b: + b.play(FadeOut(VGroup(gr, marca, base, uno, rr)), run_time=0.45) + t = VGroup( + self.fit(Text("nadie pudo demostrar", font=FONT, font_size=50, + weight=BOLD, color=WHITE), 8.2), + self.fit(Text("que pasa SIEMPRE", font=FONT, font_size=54, + weight=BOLD, color=ROSA), 8.2), + ).arrange(DOWN, buff=0.35).move_to(UP * 1.2) + b.play(FadeIn(t[0], shift=UP * 0.15), run_time=0.6) + b.play(FadeIn(t[1], scale=0.8), run_time=0.7) + + with self.beat(10) as b: + b.play(FadeOut(t), run_time=0.35) + cta = VGroup( + self.fit(Text("conjetura de Collatz", font=FONT, font_size=56, + weight=BOLD, color=AMBAR), 8.0), + self.fit(Text("dejá tu número abajo", font=FONT, font_size=46, + weight=BOLD, color=WHITE), 8.0), + ).arrange(DOWN, buff=0.38).move_to(UP * 0.8) + b.play(Write(cta[0]), run_time=0.9) + b.play(FadeIn(cta[1], shift=UP * 0.15), run_time=0.6) + + self.finish() -- cgit v1.2.3