aboutsummaryrefslogtreecommitdiffstats
path: root/scenes/v17_cicloide.py
diff options
context:
space:
mode:
authorElvis Claros Castro <elvis@claros.ar>2026-09-26 20:50:41 -0300
committerElvis Claros Castro <elvis@claros.ar>2026-09-26 20:50:41 -0300
commitfafaebb051907a848a9406f9da19669c81a83a3b (patch)
treec30ea26e6b549e5523af2bae5c39569e9a946b12 /scenes/v17_cicloide.py
parent59355909f2de9236af8168a26c70bcf6caa3b285 (diff)
download100cia-videos-main.tar.gz
100cia-videos-main.zip
Translate code, comments and logs to English; English README; configurable paths and env varsHEADmain
Identifiers, docstrings, comments and console messages are now in English. Narration, subtitles and on-screen text stay in Spanish (they are the video content). The Blender <-> Godot physics protocol uses English keys and body prefixes chosen to keep the original creation order, so cached simulations and renders stay bit-identical. The old Spanish environment variable names are still accepted.
Diffstat (limited to 'scenes/v17_cicloide.py')
-rw-r--r--scenes/v17_cicloide.py188
1 files changed, 94 insertions, 94 deletions
diff --git a/scenes/v17_cicloide.py b/scenes/v17_cicloide.py
index 5e6d4b9..79b9281 100644
--- a/scenes/v17_cicloide.py
+++ b/scenes/v17_cicloide.py
@@ -1,30 +1,30 @@
# -*- coding: utf-8 -*-
-"""La braquistocrona: la recta pierde contra la cicloide.
-Todo el movimiento sale de la fisica real (caida libre sin rozamiento)."""
+"""The brachistochrone: the straight line loses to the cycloid.
+All motion comes from real physics (frictionless free fall)."""
import sys, os, math
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from manim import *
from tiktok import *
-TH1 = 4.0553 # angulo final: da D/H = 3, la curva pasa por debajo
+TH1 = 4.0553 # final angle: gives D/H = 3, the curve dips below
DX = 7.0
RR = DX / (TH1 - math.sin(TH1))
HH = RR * (1 - math.cos(TH1))
X0, Y0 = -3.5, 3.15
-T_C = 1.55 # lo que tarda la cicloide en pantalla
-G = RR * (TH1 / T_C) ** 2 # gravedad ajustada a ese tiempo
+T_C = 1.55 # how long the cycloid takes on screen
+G = RR * (TH1 / T_C) ** 2 # gravity tuned to that time
LL = math.hypot(DX, HH)
AA = G * HH / LL
-T_L = math.sqrt(2 * LL / AA) # 2,18 s: la recta llega 40% mas tarde
+T_L = math.sqrt(2 * LL / AA) # 2.18 s: the straight line arrives 40% later
P0 = np.array([X0, Y0, 0.0])
P1 = np.array([X0 + DX, Y0 - HH, 0.0])
UU = (P1 - P0) / LL
VMAX = math.sqrt(4 * G * RR)
-RW = 1.12 # rueda de la bici
+RW = 1.12 # bike wheel
XW = -PI * RW
YW = 0.55
-R2, BX, BY = 1.22, 0.0, 0.30 # cuenco de la tautocrona
+R2, BX, BY = 1.22, 0.0, 0.30 # tautochrone bowl
T_TAU = 2.0
WW = PI / (2 * T_TAU)
@@ -33,11 +33,11 @@ def cyc(th):
return np.array([X0 + RR * (th - math.sin(th)), Y0 - RR * (1 - math.cos(th)), 0.0])
-def marca(th):
+def tick_m(th):
return np.array([XW + RW * (th - math.sin(th)), YW + RW * (1 - math.cos(th)), 0.0])
-def cuenco(th):
+def bowl(th):
return np.array([BX + R2 * (th - math.sin(th)) - R2 * PI,
BY + 2 * R2 - R2 * (1 - math.cos(th)), 0.0])
@@ -48,63 +48,63 @@ def poli(f, a, b, col, w=8, n=200):
return m
-class Cicloide(TikTok):
+class Cycloid(TikTok):
NAME = "cicloide"
def construct(self):
self.prepare()
- chip = self.chip("¿Cuál gana?", AMBAR)
+ chip = self.chip("¿Cuál gana?", AMBER)
- plata = DashedLine([X0 - 0.8, Y0 + 0.66, 0], [X0 + 1.7, Y0 + 0.66, 0],
- stroke_width=3, color=GRIS, dash_length=0.1)
- pc = Dot(radius=0.19, color=AMBAR).move_to([X0 - 0.4, Y0 + 0.66, 0])
- pr = Dot(radius=0.19, color=CELESTE).move_to([X0 + 0.08, Y0 + 0.66, 0])
+ money = DashedLine([X0 - 0.8, Y0 + 0.66, 0], [X0 + 1.7, Y0 + 0.66, 0],
+ stroke_width=3, color=C_GRAY, dash_length=0.1)
+ pc = Dot(radius=0.19, color=AMBER).move_to([X0 - 0.4, Y0 + 0.66, 0])
+ pr = Dot(radius=0.19, color=C_SKY).move_to([X0 + 0.08, Y0 + 0.66, 0])
meta = DashedLine(P1 + UP * 1.35, P1 + DOWN * 0.95, stroke_width=6,
- color=VERDE, dash_length=0.14)
- rotm = Text("META", font=FONT, font_size=32, weight=BOLD, color=VERDE)
+ color=C_GREEN, dash_length=0.14)
+ rotm = Text("META", font=FONT, font_size=32, weight=BOLD, color=C_GREEN)
rotm.next_to(meta, UP, buff=0.14)
- leyenda = VGroup(
- VGroup(Dot(radius=0.15, color=AMBAR),
+ legend = VGroup(
+ VGroup(Dot(radius=0.15, color=AMBER),
Text("curva", font=FONT, font_size=38, weight=BOLD,
- color=AMBAR)).arrange(RIGHT, buff=0.22),
- VGroup(Dot(radius=0.15, color=CELESTE),
+ color=AMBER)).arrange(RIGHT, buff=0.22),
+ VGroup(Dot(radius=0.15, color=C_SKY),
Text("recta", font=FONT, font_size=38, weight=BOLD,
- color=CELESTE)).arrange(RIGHT, buff=0.22),
+ color=C_SKY)).arrange(RIGHT, buff=0.22),
).arrange(RIGHT, buff=1.3).move_to([0, -1.3, 0])
with self.beat(0) as b:
b.play(FadeIn(chip, shift=DOWN * 0.3), run_time=0.4)
- b.play(Create(plata), run_time=0.4)
+ b.play(Create(money), run_time=0.4)
b.play(FadeIn(pc, scale=0.4), FadeIn(pr, scale=0.4), run_time=0.5)
- b.play(Create(meta), FadeIn(rotm), FadeIn(leyenda), run_time=0.7)
+ b.play(Create(meta), FadeIn(rotm), FadeIn(legend), run_time=0.7)
- recta = Line(P0, P1, stroke_width=8, color=CELESTE)
- curva = poli(cyc, 0, TH1, AMBAR)
+ line_m = Line(P0, P1, stroke_width=8, color=C_SKY)
+ curve_obj = poli(cyc, 0, TH1, AMBER)
with self.beat(1) as b:
- b.play(Create(recta), run_time=0.9)
- b.play(Create(curva), run_time=max(0.9, b.floor - 1.4))
+ b.play(Create(line_m), run_time=0.9)
+ b.play(Create(curve_obj), run_time=max(0.9, b.floor - 1.4))
inter = Text("?", font=FONT, font_size=115, weight=BOLD,
color=WHITE).move_to([0.0, 1.62, 0])
with self.beat(2) as b:
b.play(FadeIn(inter, scale=0.5), run_time=0.5)
- b.play(Indicate(inter, scale_factor=1.25, color=AMBAR), run_time=0.9)
+ b.play(Indicate(inter, scale_factor=1.25, color=AMBER), run_time=0.9)
rot = Text("el más corto", font=FONT, font_size=40, weight=BOLD,
- color=CELESTE).move_to([-0.15, 3.02, 0])
+ color=C_SKY).move_to([-0.15, 3.02, 0])
with self.beat(3) as b:
b.play(FadeOut(inter), run_time=0.3)
- b.play(recta.animate.set_stroke(width=12), FadeIn(rot, shift=UP * 0.2),
+ b.play(line_m.animate.set_stroke(width=12), FadeIn(rot, shift=UP * 0.2),
run_time=0.55)
- b.play(ShowPassingFlash(recta.copy().set_stroke(WHITE, 13), time_width=0.5),
+ b.play(ShowPassingFlash(line_m.copy().set_stroke(WHITE, 13), time_width=0.5),
run_time=1.0)
- b.play(recta.animate.set_stroke(width=8), run_time=0.3)
+ b.play(line_m.animate.set_stroke(width=8), run_time=0.3)
- # --- la carrera --------------------------------------------------------
+ # --- the race ----------------------------------------------------------
T = ValueTracker(0.0)
def up_c(m):
@@ -115,16 +115,16 @@ class Cicloide(TikTok):
t = min(T.get_value(), T_L)
m.move_to(P0 + UU * (0.5 * AA * t * t))
- med = VGroup(Circle(radius=0.34, stroke_width=0, fill_color=AMBAR, fill_opacity=1),
+ med = VGroup(Circle(radius=0.34, stroke_width=0, fill_color=AMBER, fill_opacity=1),
Text("1º", font=FONT, font_size=34, weight=BOLD, color="#0B0F1A"))
med.move_to(P1 + UP * 0.72).set_opacity(0)
med.add_updater(lambda m: m.set_opacity(1.0 if T.get_value() >= T_C else 0.0))
with self.beat(4) as b:
- b.play(FadeOut(rot), FadeOut(plata), pc.animate.move_to(P0),
+ b.play(FadeOut(rot), FadeOut(money), pc.animate.move_to(P0),
pr.animate.move_to(P0), run_time=0.5)
ya = Text("¡LARGA!", font=FONT, font_size=66, weight=BOLD,
- color=VERDE).move_to([0, 1.7, 0])
+ color=C_GREEN).move_to([0, 1.7, 0])
b.play(FadeIn(ya, scale=1.7), run_time=0.3)
b.play(FadeOut(ya), run_time=0.22)
pc.add_updater(up_c)
@@ -133,38 +133,38 @@ class Cicloide(TikTok):
b.play(T.animate.set_value(T_L), run_time=T_L, rate_func=linear)
pc.clear_updaters(); pr.clear_updaters(); med.clear_updaters()
- nivel = DashedLine([X0 - 0.2, Y0 - HH, 0], [X0 + DX + 0.2, Y0 - HH, 0],
- stroke_width=4, color=GRIS, dash_length=0.12)
- fondo = cyc(PI)
- nota = Text("pasa por debajo de la meta", font=FONT, font_size=36, weight=BOLD,
- color=ROSA).move_to([0.3, -0.95, 0])
- flecha = Arrow(nota.get_top() + RIGHT * 0.9, fondo + DOWN * 0.22, buff=0.06,
- color=ROSA, stroke_width=6, max_tip_length_to_length_ratio=0.2)
+ level = DashedLine([X0 - 0.2, Y0 - HH, 0], [X0 + DX + 0.2, Y0 - HH, 0],
+ stroke_width=4, color=C_GRAY, dash_length=0.12)
+ background = cyc(PI)
+ note_txt = Text("pasa por debajo de la meta", font=FONT, font_size=36, weight=BOLD,
+ color=C_PINK).move_to([0.3, -0.95, 0])
+ arrow_m = Arrow(note_txt.get_top() + RIGHT * 0.9, background + DOWN * 0.22, buff=0.06,
+ color=C_PINK, stroke_width=6, max_tip_length_to_length_ratio=0.2)
gap = VGroup(
Text("la recta tardó", font=FONT, font_size=38, weight=BOLD, color=WHITE),
- Text("40% más", font=FONT, font_size=64, weight=BOLD, color=CELESTE),
+ Text("40% más", font=FONT, font_size=64, weight=BOLD, color=C_SKY),
).arrange(RIGHT, buff=0.3).move_to([0.0, -2.15, 0])
with self.beat(5) as b:
- b.play(FadeOut(leyenda), Create(nivel), run_time=0.45)
- b.play(FadeIn(nota, shift=UP * 0.2), GrowArrow(flecha), run_time=0.6)
+ b.play(FadeOut(legend), Create(level), run_time=0.45)
+ b.play(FadeIn(note_txt, shift=UP * 0.2), GrowArrow(arrow_m), run_time=0.6)
b.play(FadeIn(gap, shift=UP * 0.2), run_time=0.55)
- # --- por que gana: velocidad temprana ----------------------------------
+ # --- why it wins: early speed ------------------------------------------
riel_c = Rectangle(width=6.2, height=0.32, stroke_width=0, fill_color="#1B2233",
fill_opacity=1).move_to([0.0, -1.30, 0])
riel_r = riel_c.copy().move_to([0.0, -2.20, 0])
- bar_c = Rectangle(width=0.02, height=0.32, stroke_width=0, fill_color=AMBAR,
+ bar_c = Rectangle(width=0.02, height=0.32, stroke_width=0, fill_color=AMBER,
fill_opacity=1).move_to(riel_c.get_left(), LEFT)
- bar_r = Rectangle(width=0.02, height=0.32, stroke_width=0, fill_color=CELESTE,
+ bar_r = Rectangle(width=0.02, height=0.32, stroke_width=0, fill_color=C_SKY,
fill_opacity=1).move_to(riel_r.get_left(), LEFT)
- lab_c = Text("curva", font=FONT, font_size=30, weight=BOLD, color=AMBAR)
- lab_r = Text("recta", font=FONT, font_size=30, weight=BOLD, color=CELESTE)
+ lab_c = Text("curva", font=FONT, font_size=30, weight=BOLD, color=AMBER)
+ lab_r = Text("recta", font=FONT, font_size=30, weight=BOLD, color=C_SKY)
lab_c.next_to(riel_c, LEFT, buff=0.18)
lab_r.next_to(riel_r, LEFT, buff=0.18)
- izq_c, izq_r = riel_c.get_left()[0], riel_r.get_left()[0]
+ left_c, left_r = riel_c.get_left()[0], riel_r.get_left()[0]
- def barra(m, v, x0, y):
+ def bar_m(m, v, x0, y):
w = max(0.02, 6.2 * v / VMAX)
m.stretch_to_fit_width(w)
m.move_to([x0 + w / 2, y, 0])
@@ -172,13 +172,13 @@ class Cicloide(TikTok):
def ub_c(m):
t = min(T.get_value(), T_C)
th = t * math.sqrt(G / RR)
- barra(m, math.sqrt(max(0.0, 2 * G * RR * (1 - math.cos(th)))), izq_c, -1.30)
+ bar_m(m, math.sqrt(max(0.0, 2 * G * RR * (1 - math.cos(th)))), left_c, -1.30)
def ub_r(m):
- barra(m, AA * min(T.get_value(), T_L), izq_r, -2.20)
+ bar_m(m, AA * min(T.get_value(), T_L), left_r, -2.20)
with self.beat(6) as b:
- b.play(FadeOut(VGroup(nivel, flecha, nota, gap, med)), run_time=0.35)
+ b.play(FadeOut(VGroup(level, arrow_m, note_txt, gap, med)), run_time=0.35)
T.set_value(0.0)
b.play(pc.animate.move_to(P0), pr.animate.move_to(P0),
FadeIn(VGroup(riel_c, riel_r, lab_c, lab_r, bar_c, bar_r)), run_time=0.45)
@@ -189,87 +189,87 @@ class Cicloide(TikTok):
for m in (pc, pr, bar_c, bar_r):
m.clear_updaters()
- # --- la rueda de la bici ------------------------------------------------
- viejo = VGroup(recta, curva, meta, rotm, pc, pr,
+ # --- the bike wheel -----------------------------------------------------
+ old_one = VGroup(line_m, curve_obj, meta, rotm, pc, pr,
riel_c, riel_r, lab_c, lab_r, bar_c, bar_r)
- piso = Line([-3.7, YW, 0], [3.7, YW, 0], stroke_width=6, color="#3A5487")
+ floor_obj = Line([-3.7, YW, 0], [3.7, YW, 0], stroke_width=6, color="#3A5487")
TH = ValueTracker(0.0)
- def dibujar_rueda():
+ def draw_wheel():
th = TH.get_value()
c = np.array([XW + RW * th, YW + RW, 0.0])
- g = VGroup(Circle(radius=RW, stroke_width=6, color=CELESTE).move_to(c))
+ g = VGroup(Circle(radius=RW, stroke_width=6, color=C_SKY).move_to(c))
for k in range(3):
a = -th - PI / 2 + k * TAU / 3
g.add(Line(c, c + RW * np.array([math.cos(a), math.sin(a), 0.0]),
stroke_width=4, color="#3A5487"))
return g
- rueda = always_redraw(dibujar_rueda)
- clavo = always_redraw(lambda: Dot(radius=0.14, color=AMBAR).move_to(marca(TH.get_value())))
- rastro = TracedPath(lambda: marca(TH.get_value()), stroke_color=AMBAR, stroke_width=8)
- nom = Text("CICLOIDE", font=FONT, font_size=66, weight=BOLD,
- color=AMBAR).move_to([0, -1.15, 0])
+ wheel = always_redraw(draw_wheel)
+ peg = always_redraw(lambda: Dot(radius=0.14, color=AMBER).move_to(tick_m(TH.get_value())))
+ trail = TracedPath(lambda: tick_m(TH.get_value()), stroke_color=AMBER, stroke_width=8)
+ nm_key = Text("CICLOIDE", font=FONT, font_size=66, weight=BOLD,
+ color=AMBER).move_to([0, -1.15, 0])
with self.beat(7) as b:
- b.play(FadeOut(viejo), run_time=0.4)
- b.play(Create(piso), run_time=0.3)
- b.add(rastro, rueda, clavo)
+ b.play(FadeOut(old_one), run_time=0.4)
+ b.play(Create(floor_obj), run_time=0.3)
+ b.add(trail, wheel, peg)
b.play(TH.animate.set_value(TAU), run_time=max(1.6, b.floor - 1.5),
rate_func=linear)
- b.remove(rueda, clavo, rastro)
- arco = poli(marca, 0, TAU, AMBAR)
- b.add(arco)
- b.play(FadeIn(nom, shift=UP * 0.2), run_time=0.45)
+ b.remove(wheel, peg, trail)
+ arc_m = poli(tick_m, 0, TAU, AMBER)
+ b.add(arc_m)
+ b.play(FadeIn(nm_key, shift=UP * 0.2), run_time=0.45)
# --- la tautocrona ------------------------------------------------------
- tazon = poli(cuenco, 0, TAU, AMBAR)
+ basin = poli(bowl, 0, TAU, AMBER)
TH0 = [0.30 * PI, 0.56 * PI, 0.82 * PI]
- cols = [ROSA, CELESTE, VERDE]
- bolas = VGroup(*[Dot(radius=r, color=c).move_to(cuenco(t))
+ cols = [C_PINK, C_SKY, C_GREEN]
+ bolas = VGroup(*[Dot(radius=r, color=c).move_to(bowl(t))
for t, c, r in zip(TH0, cols, (0.22, 0.175, 0.13))])
- guias = VGroup(*[DashedLine([-4.1, cuenco(t)[1], 0], cuenco(t), stroke_width=3,
+ guides = VGroup(*[DashedLine([-4.1, bowl(t)[1], 0], bowl(t), stroke_width=3,
color=c, dash_length=0.1)
for t, c in zip(TH0, cols)])
with self.beat(8) as b:
- b.play(FadeOut(VGroup(nom, piso)), run_time=0.3)
- b.play(Transform(arco, tazon), run_time=0.9)
+ b.play(FadeOut(VGroup(nm_key, floor_obj)), run_time=0.3)
+ b.play(Transform(arc_m, basin), run_time=0.9)
b.play(LaggedStart(*[FadeIn(d, scale=0.5) for d in bolas], lag_ratio=0.25),
run_time=0.8)
- b.play(Create(guias), run_time=0.5)
+ b.play(Create(guides), run_time=0.5)
TT = ValueTracker(0.0)
- def soltar(th0):
+ def drop_at(th0):
def u(m):
c = math.cos(th0 / 2) * math.cos(WW * TT.get_value())
- m.move_to(cuenco(2 * math.acos(max(-1.0, min(1.0, c)))))
+ m.move_to(bowl(2 * math.acos(max(-1.0, min(1.0, c)))))
return u
with self.beat(9) as b:
- b.play(FadeOut(guias), run_time=0.25)
+ b.play(FadeOut(guides), run_time=0.25)
for d, t0 in zip(bolas, TH0):
- d.add_updater(soltar(t0))
+ d.add_updater(drop_at(t0))
b.play(TT.animate.set_value(T_TAU), run_time=T_TAU, rate_func=linear)
for d in bolas:
d.clear_updaters()
juntas = Text("las tres, juntas", font=FONT, font_size=58, weight=BOLD,
- color=VERDE).move_to([0, -1.5, 0])
+ color=C_GREEN).move_to([0, -1.5, 0])
b.play(Flash(bolas[0], color=WHITE, flash_radius=0.9, num_lines=18),
FadeIn(juntas, shift=UP * 0.25), run_time=0.7)
- cierre = VGroup(
- Text("1696", font=FONT, font_size=76, weight=BOLD, color=AMBAR),
+ closing = VGroup(
+ Text("1696", font=FONT, font_size=76, weight=BOLD, color=AMBER),
Text("Bernoulli desafía", font=FONT, font_size=44, weight=BOLD, color=WHITE),
Text("a los matemáticos", font=FONT, font_size=44, weight=BOLD, color=WHITE),
- Text("Newton lo resuelve", font=FONT, font_size=46, weight=BOLD, color=VERDE),
- Text("esa misma noche", font=FONT, font_size=46, weight=BOLD, color=VERDE),
+ Text("Newton lo resuelve", font=FONT, font_size=46, weight=BOLD, color=C_GREEN),
+ Text("esa misma noche", font=FONT, font_size=46, weight=BOLD, color=C_GREEN),
).arrange(DOWN, buff=0.26).move_to(UP * 0.75)
with self.beat(10) as b:
- b.play(FadeOut(VGroup(arco, bolas, juntas)), run_time=0.4)
- b.play(FadeIn(cierre[:3], shift=UP * 0.25), run_time=0.7)
- b.play(FadeIn(cierre[3:], shift=UP * 0.25), run_time=0.7)
+ b.play(FadeOut(VGroup(arc_m, bolas, juntas)), run_time=0.4)
+ b.play(FadeIn(closing[:3], shift=UP * 0.25), run_time=0.7)
+ b.play(FadeIn(closing[3:], shift=UP * 0.25), run_time=0.7)
self.finish()