aboutsummaryrefslogtreecommitdiffstats
path: root/scenes/v3_cumple.py
diff options
context:
space:
mode:
authorElvis Claros Castro <elvis@claros.ar>2026-09-26 20:21:47 -0300
committerElvis Claros Castro <elvis@claros.ar>2026-09-26 20:21:47 -0300
commit59355909f2de9236af8168a26c70bcf6caa3b285 (patch)
tree686186e2086f81aa22ad25e78eb29fca3cbadc9a /scenes/v3_cumple.py
download100cia-videos-59355909f2de9236af8168a26c70bcf6caa3b285.tar.gz
100cia-videos-59355909f2de9236af8168a26c70bcf6caa3b285.zip
Import video pipeline as it was
Diffstat (limited to 'scenes/v3_cumple.py')
-rw-r--r--scenes/v3_cumple.py143
1 files changed, 143 insertions, 0 deletions
diff --git a/scenes/v3_cumple.py b/scenes/v3_cumple.py
new file mode 100644
index 0000000..ba9dd79
--- /dev/null
+++ b/scenes/v3_cumple.py
@@ -0,0 +1,143 @@
+# -*- coding: utf-8 -*-
+import sys, os, itertools
+sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
+from manim import *
+from tiktok import *
+
+N = 23
+CX, CY, R = 0.0, 2.95, 2.78
+
+
+def prob(n):
+ p = 1.0
+ for k in range(n):
+ p *= (365 - k) / 365
+ return 1 - p
+
+
+class Cumple(TikTok):
+ NAME = "cumple"
+
+ def construct(self):
+ self.prepare()
+ chip = self.chip("Paradoja del cumpleaños", CELESTE)
+
+ pts = [np.array([CX + R * np.cos(a), CY + R * np.sin(a), 0])
+ for a in np.linspace(PI / 2, PI / 2 + TAU, N, endpoint=False)]
+ people = VGroup(*[Dot(p, radius=0.17, color="#8FB8FF") for p in pts])
+
+ with self.beat(0) as b:
+ q = self.fit(Text("¿cuánta gente hace falta?", font=FONT, font_size=50,
+ weight=BOLD, color=WHITE), 8.0).move_to(UP * 3.3)
+ q2 = self.fit(Text("para que dos cumplan el mismo día", font=FONT,
+ font_size=36, color=GRIS), 8.0).next_to(q, DOWN, buff=0.35)
+ b.play(FadeIn(chip, shift=DOWN * 0.3), run_time=0.45)
+ b.play(Write(q), run_time=0.9)
+ b.play(FadeIn(q2, shift=UP * 0.15), run_time=0.6)
+
+ with self.beat(1) as b:
+ guess = Text("¿180?", font=FONT, font_size=62, weight=BOLD, color=GRIS).move_to(UP * 0.4)
+ cross = Cross(guess, stroke_color=ROSA, stroke_width=11, scale_factor=0.75)
+ ans = Text("23", font=FONT, font_size=170, weight=BOLD, color=AMBAR).move_to(DOWN * 2.2)
+ b.play(FadeOut(VGroup(q, q2)), run_time=0.3)
+ b.play(FadeIn(guess), run_time=0.4)
+ b.play(Create(cross), run_time=0.45)
+ b.play(FadeIn(ans, scale=0.55), run_time=0.7)
+ b.play(Flash(ans, color=AMBAR, line_length=0.8, num_lines=20, flash_radius=2.0),
+ run_time=0.6)
+
+ with self.beat(2) as b:
+ b.play(FadeOut(VGroup(guess, cross)),
+ ans.animate.scale(0.40).move_to(DOWN * 2.8), run_time=0.6)
+ lbl = Text("personas → 50%", font=FONT, font_size=38, weight=BOLD, color=VERDE)
+ lbl.next_to(ans, RIGHT, buff=0.35)
+ grp = VGroup(ans, lbl)
+ grp.move_to(DOWN * 2.8)
+ b.play(LaggedStart(*[GrowFromCenter(d) for d in people], lag_ratio=0.06),
+ run_time=1.1)
+ b.play(FadeIn(lbl, shift=LEFT * 0.2), run_time=0.5)
+
+ # --- el error: uno contra todos ---
+ with self.beat(3) as b:
+ hero = people[0]
+ spokes = VGroup(*[Line(pts[0], pts[k], stroke_width=3.5, color=AMBAR)
+ for k in range(1, N)])
+ cnt = Text("22 comparaciones", font=FONT, font_size=40, weight=BOLD,
+ color=AMBAR).move_to(DOWN * 1.3)
+ b.play(hero.animate.set_color(AMBAR).scale(1.6), run_time=0.4)
+ b.play(LaggedStart(*[Create(s) for s in spokes], lag_ratio=0.05), run_time=1.3)
+ b.play(FadeIn(cnt, shift=UP * 0.15), run_time=0.5)
+
+ # --- todos contra todos ---
+ pairs = list(itertools.combinations(range(N), 2))
+ with self.beat(4) as b:
+ chords = VGroup(*[Line(pts[i], pts[j], stroke_width=1.7,
+ color="#4CC9F0", stroke_opacity=0.5)
+ for i, j in pairs])
+ b.play(FadeOut(spokes), FadeOut(cnt),
+ hero.animate.set_color("#8FB8FF").scale(1 / 1.6), run_time=0.5)
+ b.play(LaggedStart(*[Create(c) for c in chords], lag_ratio=0.004),
+ run_time=max(1.4, b.floor - 0.9))
+
+ with self.beat(5) as b:
+ big = Text("253", font=FONT, font_size=112, weight=BOLD, color=CELESTE)
+ cap = Text("parejas posibles", font=FONT, font_size=38, weight=BOLD, color=WHITE)
+ box = VGroup(big, cap).arrange(DOWN, buff=0.18).move_to(DOWN * 1.1)
+ b.play(FadeIn(big, scale=0.6), run_time=0.6)
+ b.play(FadeIn(cap, shift=UP * 0.15), run_time=0.5)
+
+ with self.beat(6) as b:
+ b.play(Circumscribe(box, color=CELESTE, buff=0.35, stroke_width=6), run_time=1.0)
+ b.wait(0.3)
+
+ # --- la curva ---
+ axes = Axes(x_range=[0, 70, 10], y_range=[0, 100, 25],
+ x_length=7.4, y_length=5.0,
+ axis_config=dict(color="#4A5878", stroke_width=4,
+ include_tip=False, font_size=26),
+ y_axis_config=dict(include_numbers=True,
+ numbers_to_include=[0, 50, 100]))
+ axes.move_to(UP * 2.15)
+ xlab = Text("personas", font=FONT, font_size=30, color=GRIS).next_to(axes, DOWN, buff=0.3)
+ curve = axes.plot(lambda n: prob(int(n)) * 100, x_range=[1, 70, 1],
+ color=AMBAR, stroke_width=8)
+
+ with self.beat(7) as b:
+ b.play(FadeOut(VGroup(people, chords, box, grp)), run_time=0.5)
+ b.play(Create(axes), FadeIn(xlab), run_time=0.8)
+ b.play(Create(curve), run_time=max(0.9, b.floor - 1.5))
+
+ marks = VGroup()
+
+ def mark(n, txt, col):
+ d = Dot(axes.c2p(n, prob(n) * 100), radius=0.13, color=col)
+ t = Text(txt, font=FONT, font_size=34, weight=BOLD, color=col)
+ t.next_to(d, DOWN, buff=0.28)
+ return VGroup(d, t)
+
+ with self.beat(7 if False else 8) as b:
+ m50 = mark(50, "97%", VERDE)
+ m50[1].next_to(m50[0], DOWN, buff=0.35).shift(LEFT * 0.35)
+ m30 = mark(30, "70%", CELESTE)
+ m30[1].next_to(m30[0], RIGHT, buff=0.3).shift(DOWN * 0.35)
+ b.play(FadeIn(m30[0], scale=0.5), Write(m30[1]), run_time=0.7)
+ b.wait(0.2)
+ marks.add(m30)
+ b.play(FadeIn(m50[0], scale=0.5), Write(m50[1]), run_time=0.7)
+ marks.add(m50)
+
+ with self.beat(9) as b:
+ m70 = mark(70, "99,9%", AMBAR)
+ m70[1].next_to(m70[0], UP, buff=0.3).shift(LEFT * 0.55)
+ b.play(FadeIn(m70[0], scale=0.5), Write(m70[1]), run_time=0.8)
+ b.play(Flash(m70[0], color=AMBAR, line_length=0.5, num_lines=16,
+ flash_radius=1.0), run_time=0.7)
+ marks.add(m70)
+
+ with self.beat(10) as b:
+ cta = self.fit(Text("probalo en tu grupo", font=FONT, font_size=64,
+ weight=BOLD, color=AMBAR), 7.9).move_to(DOWN * 2.1)
+ b.play(Write(cta), run_time=0.9)
+ b.play(Circumscribe(cta, color=AMBAR, buff=0.3, stroke_width=7), run_time=1.0)
+
+ self.finish()