""" SURYA — A Mathematical Journey Through Feeling Das's 14-track emotional odyssey rendered in mathematical beauty Created with Manim Community Edition """ from manim import * import numpy as np from scipy.interpolate import interp1d import random # ============================================================================ # CONFIGURATION # ============================================================================ config.background_color = "#030305" # Color palette matching the SURYA website aesthetic class SuryaColors: # Track colors INTRO = "#a78bfa" # Purple SKIN = "#f472b6" # Pink SAVED = "#22d3ee" # Cyan NOTHING = "#666666" # Grey RELIEF = "#a78bfa" # Purple NATURE = "#5eead4" # Teal DREAM = "#c4b5fd" # Soft purple IDK = "#f472b6" # Dark pink WITH_U = "#fbbf24" # Golden (THE TURN) POOR = "#fb923c" # Orange WAIT = "#a78bfa" # Purple longing RUN = "#22d3ee" # Cyan urgent MEDS = "#ef4444" # Red HOLLOW = "#fbbf24" # Golden resolution # Supporting colors DARK_BG = "#030305" SOUL_WHITE = "#ffffff" GLOW_SOFT = "#ffffff40" # ============================================================================ # CUSTOM MATHEMATICAL OBJECTS # ============================================================================ class SoulOrb(VGroup): """The persistent soul orb - heart of the journey""" def __init__(self, color=WHITE, radius=0.3, glow_radius=1.5, **kwargs): super().__init__(**kwargs) # Core orb self.core = Dot(radius=radius, color=color) self.core.set_fill(color, opacity=1) # Glow layers (gaussian-like falloff) self.glow_layers = VGroup() for i in range(8): factor = (i + 1) / 8 glow = Circle(radius=radius + glow_radius * factor) opacity = 0.3 * (1 - factor) ** 2 glow.set_stroke(color, width=2, opacity=opacity) glow.set_fill(color, opacity=opacity * 0.3) self.glow_layers.add(glow) # Pulsing ring self.ring = Circle(radius=radius * 2) self.ring.set_stroke(color, width=1, opacity=0.5) self.add(self.glow_layers, self.core, self.ring) self.color = color def pulse(self, scale_factor=1.3, run_time=1): return AnimationGroup( self.ring.animate.scale(scale_factor).set_opacity(0), rate_func=smooth ) class Spirograph(VMobject): """Parametric spirograph curves - mathematical beauty""" def __init__(self, R=3, r=1, d=1.5, color=WHITE, num_points=1000, **kwargs): super().__init__(**kwargs) self.R, self.r, self.d = R, r, d t = np.linspace(0, 2 * np.pi * self._lcm_period(), num_points) # Hypotrochoid equations x = (R - r) * np.cos(t) + d * np.cos((R - r) / r * t) y = (R - r) * np.sin(t) - d * np.sin((R - r) / r * t) points = [np.array([x[i], y[i], 0]) for i in range(len(t))] self.set_points_smoothly(points) self.set_stroke(color, width=2, opacity=0.8) def _lcm_period(self): from math import gcd r_int, R_int = int(self.r * 100), int(self.R * 100) return r_int // gcd(r_int, R_int) class LissajousCurve(VMobject): """Lissajous figures - chaos and confusion""" def __init__(self, a=3, b=4, delta=np.pi/2, color=WHITE, **kwargs): super().__init__(**kwargs) t = np.linspace(0, 2 * np.pi, 1000) x = 2 * np.sin(a * t + delta) y = 2 * np.sin(b * t) points = [np.array([x[i], y[i], 0]) for i in range(len(t))] self.set_points_smoothly(points) self.set_stroke(color, width=2) class FlowerOfLife(VGroup): """Sacred geometry - spiritual moments""" def __init__(self, rings=2, radius=0.5, color=WHITE, **kwargs): super().__init__(**kwargs) centers = [ORIGIN] for ring in range(1, rings + 1): for i in range(6 * ring): angle = i * TAU / (6 * ring) dist = radius * ring * np.sqrt(3) centers.append(np.array([ dist * np.cos(angle), dist * np.sin(angle), 0 ])) for center in centers[:19]: # Classic 19 circles circle = Circle(radius=radius, color=color) circle.move_to(center) circle.set_stroke(color, width=1.5, opacity=0.6) self.add(circle) class GoldenSpiral(VMobject): """Golden ratio spiral - resolution and beauty""" def __init__(self, turns=4, color=GOLD, **kwargs): super().__init__(**kwargs) phi = (1 + np.sqrt(5)) / 2 # Golden ratio t = np.linspace(0, turns * 2 * np.pi, 500) # Logarithmic spiral with golden ratio r = 0.1 * phi ** (t / (2 * np.pi)) x = r * np.cos(t) y = r * np.sin(t) points = [np.array([x[i], y[i], 0]) for i in range(len(t))] self.set_points_smoothly(points) self.set_stroke(color, width=3) class FractalTree(VGroup): """Branching fractals - nature and growth""" def __init__(self, depth=6, length=2, angle=25, color=GREEN, **kwargs): super().__init__(**kwargs) self._build_tree(ORIGIN, UP * length, depth, length, angle, color) def _build_tree(self, start, direction, depth, length, angle, color): if depth == 0: return end = start + direction branch = Line(start, end, color=color) branch.set_stroke(width=depth * 0.8, opacity=0.3 + 0.1 * depth) self.add(branch) # Recursive branches new_length = length * 0.7 left_dir = rotate_vector(direction, angle * DEGREES) * 0.7 right_dir = rotate_vector(direction, -angle * DEGREES) * 0.7 self._build_tree(end, left_dir, depth - 1, new_length, angle, color) self._build_tree(end, right_dir, depth - 1, new_length, angle, color) class VoronoiFragments(VGroup): """Voronoi diagram - fragmentation and emptiness""" def __init__(self, num_points=30, color=WHITE, **kwargs): super().__init__(**kwargs) # Generate random points points = np.random.uniform(-4, 4, (num_points, 2)) # Create approximate Voronoi cells using circles for point in points: cell = Dot(point=[point[0], point[1], 0], radius=0.05, color=color) cell.set_fill(color, opacity=0.3) self.add(cell) # Add connecting lines for other in points: if np.linalg.norm(point - other) < 2 and not np.array_equal(point, other): mid = (point + other) / 2 angle = np.arctan2(other[1] - point[1], other[0] - point[0]) line = Line( [mid[0] - np.sin(angle), mid[1] + np.cos(angle), 0], [mid[0] + np.sin(angle), mid[1] - np.cos(angle), 0], color=color ) line.set_stroke(width=0.5, opacity=0.2) self.add(line) class ParticleField(VGroup): """Particles following mathematical fields""" def __init__(self, num_particles=100, color=WHITE, **kwargs): super().__init__(**kwargs) for _ in range(num_particles): x = random.uniform(-7, 7) y = random.uniform(-4, 4) size = random.uniform(0.02, 0.06) opacity = random.uniform(0.2, 0.6) particle = Dot(point=[x, y, 0], radius=size, color=color) particle.set_fill(color, opacity=opacity) self.add(particle) class StrangeAttractor(VMobject): """Lorenz-like strange attractor for chaos moments""" def __init__(self, color=RED, **kwargs): super().__init__(**kwargs) # Simplified attractor visualization sigma, rho, beta = 10, 28, 8/3 dt = 0.01 x, y, z = 0.1, 0, 0 points = [] for _ in range(3000): dx = sigma * (y - x) * dt dy = (x * (rho - z) - y) * dt dz = (x * y - beta * z) * dt x, y, z = x + dx, y + dy, z + dz points.append(np.array([x * 0.1, (z - 25) * 0.1, 0])) self.set_points_smoothly(points) self.set_stroke(color, width=1, opacity=0.7) # ============================================================================ # TRACK ANIMATIONS # ============================================================================ class Track01_Skin(Scene): """Alienation - "don't fit in my own skin" """ def construct(self): # Create distorted soul trying to find its shape soul = SoulOrb(color=SuryaColors.SKIN, radius=0.3) self.play(FadeIn(soul, scale=0.5), run_time=2) # Morphing spirograph representing identity struggle spiro1 = Spirograph(R=3, r=0.7, d=1.2, color=SuryaColors.SKIN) spiro2 = Spirograph(R=3, r=1.3, d=0.8, color=SuryaColors.SKIN) spiro1.scale(0.8) spiro2.scale(0.8) self.play(Create(spiro1), run_time=3) # Soul pulsates uncomfortably self.play( soul.animate.scale(0.7), spiro1.animate.set_opacity(0.5), run_time=1 ) self.play( soul.animate.scale(1.3), run_time=1 ) # Transform to different identity self.play( Transform(spiro1, spiro2), soul.animate.scale(0.8), run_time=4 ) # Particles of self floating away particles = ParticleField(50, color=SuryaColors.SKIN) self.play(FadeIn(particles, lag_ratio=0.1), run_time=2) # Everything fades with lingering unease self.play( FadeOut(spiro1), FadeOut(particles), soul.animate.scale(0.5).set_opacity(0.3), run_time=3 ) self.wait(1) class Track02_USavedMe(Scene): """Hope emerges - "you saved me from my broken soul" """ def construct(self): # Broken soul fragments soul = SoulOrb(color=SuryaColors.SAVED, radius=0.2) soul.set_opacity(0.5) # Fragments scattered fragments = VGroup(*[ Dot(point=[random.uniform(-2, 2), random.uniform(-2, 2), 0], radius=0.05, color=SuryaColors.SAVED) for _ in range(20) ]) self.play(FadeIn(fragments, lag_ratio=0.1), run_time=2) # Fragments begin to coalesce self.play( *[f.animate.move_to(ORIGIN) for f in fragments], run_time=3, rate_func=smooth ) # Soul emerges whole self.play( FadeOut(fragments), FadeIn(soul, scale=2), run_time=2 ) # Hopeful spirograph expands outward spiro = Spirograph(R=4, r=1.5, d=2, color=SuryaColors.SAVED) spiro.scale(0) self.add(spiro) self.play( spiro.animate.scale(0.7), soul.animate.scale(1.5).set_opacity(1), run_time=4 ) # Sacred geometry appears - spiritual awakening flower = FlowerOfLife(rings=2, radius=0.6, color=SuryaColors.SAVED) flower.set_opacity(0) self.add(flower) self.play( flower.animate.set_opacity(0.4), spiro.animate.set_opacity(0.3), run_time=3 ) # Gentle pulsing in harmony self.play( soul.animate.scale(1.2), flower.animate.scale(1.1), run_time=1.5 ) self.play( soul.animate.scale(1/1.2), flower.animate.scale(1/1.1), run_time=1.5 ) self.play( FadeOut(spiro, flower), soul.animate.scale(0.6), run_time=2 ) class Track03_Nothing(Scene): """Emptiness - "I lost my heart, now I feel nothing" """ def construct(self): # Soul starts visible but will fade soul = SoulOrb(color=SuryaColors.NOTHING, radius=0.3) self.add(soul) # Voronoi fragmentation - self breaking apart voronoi = VoronoiFragments(num_points=25, color=SuryaColors.NOTHING) # Soul slowly dims self.play( soul.animate.scale(0.7).set_opacity(0.5), run_time=3 ) # Fragments appear self.play(Create(voronoi), run_time=4) # Everything becomes grey and distant grey_circle = Circle(radius=3, color=SuryaColors.NOTHING) grey_circle.set_stroke(width=1, opacity=0.2) grey_circle.set_fill(SuryaColors.NOTHING, opacity=0.05) self.play( FadeIn(grey_circle), soul.animate.scale(0.3).set_opacity(0.2), voronoi.animate.set_opacity(0.1), run_time=4 ) # Hollow pulsing - mechanical, lifeless for _ in range(2): self.play( grey_circle.animate.scale(1.1), run_time=1, rate_func=there_and_back ) # Static emptiness self.wait(2) # Fragments scatter into void self.play( FadeOut(voronoi, shift=UP * 2), FadeOut(grey_circle), soul.animate.set_opacity(0.1), run_time=3 ) class Track04_SweetRelief(Scene): """Haunted - "seeing ghosts around my throat" """ def construct(self): soul = SoulOrb(color=SuryaColors.RELIEF, radius=0.25) self.add(soul) # Ghost-like spiraling forms ghosts = VGroup() for i in range(5): ghost = Spirograph(R=2 + i * 0.3, r=0.5, d=1 + i * 0.2, color=SuryaColors.RELIEF) ghost.scale(0.5) ghost.set_opacity(0.1 + i * 0.05) ghost.rotate(i * PI / 5) ghosts.add(ghost) self.play( *[Create(g) for g in ghosts], run_time=4, lag_ratio=0.3 ) # Ghosts circle the soul menacingly self.play( Rotate(ghosts, PI, about_point=ORIGIN), soul.animate.scale(0.8), run_time=4 ) # Soul struggles self.play( soul.animate.shift(UP * 0.3), run_time=0.5 ) self.play( soul.animate.shift(DOWN * 0.3), run_time=0.5 ) # Ghosts close in self.play( ghosts.animate.scale(0.7), soul.animate.set_opacity(0.6), run_time=3 ) # Brief moment of relief (ghosts recede slightly) self.play( ghosts.animate.scale(1.3).set_opacity(0.1), soul.animate.scale(1.2).set_opacity(1), run_time=2 ) self.play( FadeOut(ghosts), run_time=2 ) class Track05_Tiptoe(Scene): """Tense, cautious movement""" def construct(self): soul = SoulOrb(color=SuryaColors.RELIEF, radius=0.2) soul.shift(LEFT * 4) self.add(soul) # Careful path - Lissajous representing caution path = LissajousCurve(a=3, b=2, delta=PI/4, color=SuryaColors.RELIEF) path.set_opacity(0.3) self.play(Create(path), run_time=2) # Soul moves carefully along path # Small, hesitant steps positions = [LEFT * 3, LEFT * 2, LEFT * 1, ORIGIN, RIGHT * 1, RIGHT * 2, RIGHT * 3] for pos in positions: self.play( soul.animate.move_to(pos), run_time=0.8, rate_func=smooth ) # Pause - checking surroundings self.wait(0.3) # Tension builds - path becomes more complex path2 = LissajousCurve(a=5, b=4, delta=PI/3, color=SuryaColors.RELIEF) path2.set_opacity(0.2) self.play( Transform(path, path2), soul.animate.move_to(ORIGIN), run_time=3 ) # Soul retreats to center, bracing self.play( soul.animate.scale(0.7), path.animate.set_opacity(0.1), run_time=2 ) self.play(FadeOut(path), run_time=1) class Track06_NaturesCall(Scene): """Peaceful interlude - "thank you for joining us" """ def construct(self): soul = SoulOrb(color=SuryaColors.NATURE, radius=0.3) self.play(FadeIn(soul), run_time=2) # Fractal tree grows - nature emerging tree = FractalTree(depth=6, length=1.5, color=SuryaColors.NATURE) tree.shift(DOWN * 2) tree.set_opacity(0) self.add(tree) self.play( tree.animate.set_opacity(0.6), run_time=5 ) # Particles like leaves/pollen floating up particles = VGroup() for _ in range(50): p = Dot( point=[random.uniform(-4, 4), random.uniform(-3, -2), 0], radius=random.uniform(0.02, 0.05), color=SuryaColors.NATURE ) p.set_opacity(random.uniform(0.3, 0.7)) particles.add(p) self.play(FadeIn(particles, lag_ratio=0.05), run_time=2) # Particles float upward peacefully self.play( *[p.animate.shift(UP * random.uniform(4, 6)) for p in particles], run_time=6, rate_func=smooth ) # Golden ratio spiral emerges - nature's mathematics spiral = GoldenSpiral(turns=3, color=SuryaColors.NATURE) spiral.scale(0.3) spiral.set_opacity(0) self.play( spiral.animate.set_opacity(0.5).scale(2), soul.animate.scale(1.3), run_time=4 ) # Peaceful conclusion self.play( tree.animate.set_opacity(0.2), spiral.animate.set_opacity(0.2), run_time=3 ) self.play( FadeOut(tree, spiral, particles), run_time=2 ) class Track07_Dreamcatcher(Scene): """Falling - "falling through the cracks" """ def construct(self): soul = SoulOrb(color=SuryaColors.DREAM, radius=0.3) soul.shift(UP * 3) self.play(FadeIn(soul), run_time=1) # Dreamcatcher web - sacred geometry web = VGroup() for i in range(6): angle = i * PI / 3 line = Line(ORIGIN, 3 * np.array([np.cos(angle), np.sin(angle), 0])) line.set_stroke(SuryaColors.DREAM, width=1, opacity=0.4) web.add(line) for r in [0.5, 1, 1.5, 2, 2.5]: circle = Circle(radius=r, color=SuryaColors.DREAM) circle.set_stroke(width=1, opacity=0.3) web.add(circle) self.play(Create(web), run_time=3) # Soul begins to fall through the web self.play( soul.animate.shift(DOWN * 2), run_time=2, rate_func=rate_functions.ease_in_quad ) # Passing through layers - web pulses for _ in range(3): self.play( web.animate.scale(1.1).set_opacity(0.2), run_time=0.5 ) self.play( web.animate.scale(1/1.1).set_opacity(0.4), run_time=0.5 ) self.play( soul.animate.shift(DOWN * 1), run_time=1.5 ) # Soul falls through completely self.play( soul.animate.shift(DOWN * 2).scale(0.5).set_opacity(0.4), web.animate.set_opacity(0.1), run_time=3, rate_func=rate_functions.ease_in_quad ) self.play(FadeOut(web), run_time=1) class Track08_IDK(Scene): """Confusion - "drugs don't work on me no more" """ def construct(self): soul = SoulOrb(color=SuryaColors.IDK, radius=0.25) soul.set_opacity(0.6) self.add(soul) # Strange attractor - chaos and confusion attractor = StrangeAttractor(color=SuryaColors.IDK) attractor.scale(0.5) self.play(Create(attractor), run_time=5) # Soul wanders erratically random_points = [ np.array([random.uniform(-2, 2), random.uniform(-1.5, 1.5), 0]) for _ in range(8) ] for point in random_points: self.play( soul.animate.move_to(point), run_time=0.6, rate_func=rate_functions.ease_in_out_sine ) # Multiple Lissajous curves - mind racing curves = VGroup() for i in range(4): curve = LissajousCurve( a=random.randint(2, 5), b=random.randint(2, 5), delta=random.uniform(0, PI), color=SuryaColors.IDK ) curve.scale(0.5 + i * 0.2) curve.set_opacity(0.2) curves.add(curve) self.play( *[Create(c) for c in curves], run_time=3, lag_ratio=0.2 ) # Everything spins in confusion self.play( Rotate(curves, PI, about_point=ORIGIN), soul.animate.move_to(ORIGIN).scale(0.8), run_time=4 ) # Collapse into uncertainty self.play( FadeOut(attractor, curves), soul.animate.scale(0.5).set_opacity(0.4), run_time=3 ) class Track09_WithU(Scene): """THE TURN - "floating through the stars" - Two souls meet""" def construct(self): # Primary soul soul1 = SoulOrb(color=WHITE, radius=0.3) soul1.shift(LEFT * 3) # Second soul appears - golden warmth soul2 = SoulOrb(color=SuryaColors.WITH_U, radius=0.25) soul2.shift(RIGHT * 5) soul2.set_opacity(0) self.play(FadeIn(soul1), run_time=2) # Stars begin appearing stars = VGroup() for _ in range(80): star = Dot( point=[random.uniform(-7, 7), random.uniform(-4, 4), 0], radius=random.uniform(0.01, 0.04), color=WHITE ) star.set_opacity(0) stars.add(star) self.add(stars) self.play( *[s.animate.set_opacity(random.uniform(0.3, 0.9)) for s in stars], run_time=3, lag_ratio=0.02 ) # Second soul emerges from the stars self.play( soul2.animate.set_opacity(1).shift(LEFT * 2), run_time=3 ) # Souls move toward each other self.play( soul1.animate.shift(RIGHT * 1.5), soul2.animate.shift(LEFT * 1.5), run_time=3, rate_func=smooth ) # They begin orbiting each other - binary star system orbit_center = (soul1.get_center() + soul2.get_center()) / 2 # Golden spiral emerges between them spiral = GoldenSpiral(turns=4, color=SuryaColors.WITH_U) spiral.scale(0.4) spiral.move_to(orbit_center) spiral.set_opacity(0) self.play(spiral.animate.set_opacity(0.5), run_time=2) # Orbiting animation for _ in range(2): self.play( Rotate(soul1, PI, about_point=orbit_center), Rotate(soul2, PI, about_point=orbit_center), Rotate(spiral, PI/2, about_point=orbit_center), run_time=4, rate_func=smooth ) # Souls move closer, colors blend self.play( soul1.animate.scale(1.2).move_to(orbit_center + LEFT * 0.3), soul2.animate.scale(1.2).move_to(orbit_center + RIGHT * 0.3), spiral.animate.scale(1.5), run_time=3 ) # Radiant climax - sacred geometry flower = FlowerOfLife(rings=2, radius=0.5, color=SuryaColors.WITH_U) flower.move_to(orbit_center) flower.set_opacity(0) self.play( flower.animate.set_opacity(0.4).scale(1.2), stars.animate.set_opacity(0.8), run_time=3 ) # Final pulse of connection self.play( soul1.animate.scale(1.3), soul2.animate.scale(1.3), flower.animate.scale(1.3), run_time=1.5 ) self.play( soul1.animate.scale(1/1.3), soul2.animate.scale(1/1.3), flower.animate.scale(1/1.3), run_time=1.5 ) # Gentle fade maintaining connection self.play( flower.animate.set_opacity(0.1), spiral.animate.set_opacity(0.2), stars.animate.set_opacity(0.3), run_time=3 ) class Track10_PoorYouPoorMe(Scene): """Bittersweet - "you left your cardigan on my bed" """ def construct(self): # Two souls, but one is fading soul1 = SoulOrb(color=SuryaColors.POOR, radius=0.3) soul2 = SoulOrb(color=SuryaColors.WITH_U, radius=0.25) soul2.shift(RIGHT * 1.5) self.play(FadeIn(soul1, soul2), run_time=2) # Spirograph of intertwined paths spiro = Spirograph(R=3, r=1.8, d=1.5, color=SuryaColors.POOR) spiro.scale(0.6) spiro.set_opacity(0.4) self.play(Create(spiro), run_time=4) # One soul begins to drift away self.play( soul2.animate.shift(RIGHT * 2).set_opacity(0.6), run_time=3 ) # Lingering warmth - particles like memories memories = VGroup() for _ in range(30): m = Dot( point=soul2.get_center() + np.array([ random.uniform(-1, 1), random.uniform(-1, 1), 0 ]), radius=0.03, color=SuryaColors.WITH_U ) m.set_opacity(0.5) memories.add(m) self.play(FadeIn(memories), run_time=2) # Memories drift toward remaining soul self.play( *[m.animate.move_to( soul1.get_center() + np.array([random.uniform(-0.5, 0.5), random.uniform(-0.5, 0.5), 0]) ) for m in memories], soul2.animate.shift(RIGHT * 2).set_opacity(0.2), run_time=4 ) # Bittersweet pulse self.play( soul1.animate.scale(1.2), spiro.animate.set_opacity(0.6), run_time=2 ) self.play( soul1.animate.scale(1/1.2), spiro.animate.set_opacity(0.3), run_time=2 ) self.play( FadeOut(soul2, memories, spiro), run_time=3 ) class Track11_Wait4U(Scene): """Longing - waiting""" def construct(self): soul = SoulOrb(color=SuryaColors.WAIT, radius=0.3) self.play(FadeIn(soul), run_time=2) # Concentric circles - time passing, waiting circles = VGroup() for i in range(8): c = Circle(radius=0.5 + i * 0.4, color=SuryaColors.WAIT) c.set_stroke(width=1, opacity=0.3 - i * 0.03) circles.add(c) self.play( *[Create(c) for c in circles], run_time=3, lag_ratio=0.3 ) # Slow pulsing - patient waiting for _ in range(3): self.play( circles.animate.scale(1.1), soul.animate.scale(0.9), run_time=2 ) self.play( circles.animate.scale(1/1.1), soul.animate.scale(1/0.9), run_time=2 ) # Spiral of longing spiral = GoldenSpiral(turns=5, color=SuryaColors.WAIT) spiral.scale(0.3) spiral.set_opacity(0) self.play( spiral.animate.set_opacity(0.4).scale(2), circles.animate.set_opacity(0.1), run_time=4 ) self.play( FadeOut(circles, spiral), run_time=2 ) class Track12_RunToU(Scene): """Urgency - "if the sky was falling I would run to you" """ def construct(self): # Soul starts at edge, urgent energy soul = SoulOrb(color=SuryaColors.RUN, radius=0.3) soul.shift(LEFT * 5) # Target - the other soul (faint in distance) target = SoulOrb(color=SuryaColors.WITH_U, radius=0.25) target.shift(RIGHT * 5) target.set_opacity(0.3) self.play(FadeIn(soul, target), run_time=1) # Streaking particles - speed lines speed_lines = VGroup() for _ in range(20): y = random.uniform(-3, 3) line = Line(LEFT * 7, RIGHT * 7, color=SuryaColors.RUN) line.shift(UP * y) line.set_stroke(width=1, opacity=0.2) speed_lines.add(line) self.play( *[Create(l) for l in speed_lines], run_time=1 ) # Running motion - urgent spirograph spiro = Spirograph(R=2, r=0.3, d=2, color=SuryaColors.RUN) spiro.scale(0.3) spiro.move_to(soul.get_center()) spiro.set_opacity(0) # Urgent movement toward target self.play( soul.animate.shift(RIGHT * 4), spiro.animate.shift(RIGHT * 4).set_opacity(0.5), target.animate.set_opacity(0.6), Rotate(spiro, TAU * 2, about_point=soul.get_center()), run_time=3, rate_func=rate_functions.ease_in_quad ) # Final push self.play( soul.animate.shift(RIGHT * 4), target.animate.shift(LEFT * 1).set_opacity(1), speed_lines.animate.set_opacity(0.5), run_time=2, rate_func=rate_functions.ease_out_quad ) # Collision/embrace - burst of energy burst = VGroup() for i in range(12): angle = i * PI / 6 ray = Line(ORIGIN, 2 * np.array([np.cos(angle), np.sin(angle), 0])) ray.set_stroke(SuryaColors.RUN, width=3, opacity=0.6) burst.add(ray) burst.move_to(RIGHT * 2) self.play( FadeIn(burst, scale=0.5), soul.animate.move_to(RIGHT * 2).scale(1.3), target.animate.move_to(RIGHT * 2).scale(1.3), run_time=1 ) self.play( burst.animate.scale(2).set_opacity(0), FadeOut(speed_lines, spiro), run_time=2 ) class Track13_Medications(Scene): """Struggle - "raging in my head" """ def construct(self): soul = SoulOrb(color=SuryaColors.MEDS, radius=0.3) self.play(FadeIn(soul), run_time=1) # Strange attractor - chaos in the mind attractor = StrangeAttractor(color=SuryaColors.MEDS) attractor.scale(0.6) self.play(Create(attractor), run_time=3) # Aggressive spirograph - war in the head spiros = VGroup() for i in range(3): s = Spirograph(R=2 + i, r=0.5 + i * 0.3, d=1.5, color=SuryaColors.MEDS) s.scale(0.4) s.set_opacity(0.3) s.rotate(i * PI / 3) spiros.add(s) self.play( *[Create(s) for s in spiros], run_time=3 ) # Soul shakes violently original_pos = soul.get_center() for _ in range(6): offset = np.array([random.uniform(-0.3, 0.3), random.uniform(-0.3, 0.3), 0]) self.play( soul.animate.move_to(original_pos + offset), run_time=0.15 ) self.play(soul.animate.move_to(original_pos), run_time=0.2) # Red pulses - pain for _ in range(3): pulse = Circle(radius=0.5, color=SuryaColors.MEDS) pulse.set_stroke(width=3, opacity=0.8) self.add(pulse) self.play( pulse.animate.scale(4).set_opacity(0), spiros.animate.rotate(PI/6), run_time=1 ) self.remove(pulse) # Struggle continues self.play( Rotate(attractor, PI, about_point=ORIGIN), spiros.animate.set_opacity(0.5), soul.animate.scale(0.8), run_time=3 ) # Eventual exhaustion self.play( attractor.animate.set_opacity(0.2), spiros.animate.set_opacity(0.1).scale(0.8), soul.animate.scale(0.7).set_opacity(0.6), run_time=3 ) self.play(FadeOut(attractor, spiros), run_time=2) class Track14_Hollow(Scene): """Resolution - "you took my sorrow and flew it to the moon" """ def construct(self): # Soul begins small and humble soul = SoulOrb(color=SuryaColors.HOLLOW, radius=0.2) soul.set_opacity(0.5) self.play(FadeIn(soul), run_time=2) # Stars return - hope stars = VGroup() for _ in range(100): star = Dot( point=[random.uniform(-7, 7), random.uniform(-4, 4), 0], radius=random.uniform(0.01, 0.05), color=WHITE ) star.set_opacity(0) stars.add(star) self.add(stars) self.play( *[s.animate.set_opacity(random.uniform(0.2, 0.8)) for s in stars], soul.animate.set_opacity(0.8).scale(1.2), run_time=4, lag_ratio=0.01 ) # Golden spiral - resolution through golden ratio spiral = GoldenSpiral(turns=5, color=SuryaColors.HOLLOW) spiral.scale(0.2) spiral.set_opacity(0) self.play( spiral.animate.set_opacity(0.6).scale(3), run_time=5 ) # Moon appears (large circle in upper area) moon = Circle(radius=1.5, color=SuryaColors.HOLLOW) moon.set_fill(SuryaColors.HOLLOW, opacity=0.1) moon.set_stroke(SuryaColors.HOLLOW, width=2, opacity=0.5) moon.shift(UP * 2 + RIGHT * 3) self.play(FadeIn(moon, scale=0.5), run_time=3) # Sorrow (dark particles) flying to the moon sorrow = VGroup() for _ in range(20): s = Dot( point=soul.get_center() + np.array([ random.uniform(-0.5, 0.5), random.uniform(-0.5, 0.5), 0 ]), radius=0.04, color=GREY ) sorrow.add(s) self.play(FadeIn(sorrow), run_time=1) # Sorrow flies to moon self.play( *[s.animate.move_to(moon.get_center() + np.array([ random.uniform(-0.5, 0.5), random.uniform(-0.5, 0.5), 0 ])).set_opacity(0) for s in sorrow], soul.animate.scale(1.3).set_opacity(1), run_time=4 ) # Sacred geometry finale flower = FlowerOfLife(rings=2, radius=0.6, color=SuryaColors.HOLLOW) flower.set_opacity(0) self.play( flower.animate.set_opacity(0.4), spiral.animate.set_opacity(0.8), run_time=3 ) # Final radiant pulse self.play( soul.animate.scale(1.5), flower.animate.scale(1.3), spiral.animate.scale(1.2), stars.animate.set_opacity(1), run_time=2 ) # Peaceful hold self.wait(3) # Gentle fade to completion self.play( soul.animate.scale(2).set_opacity(0.5), flower.animate.set_opacity(0.2), spiral.animate.set_opacity(0.3), stars.animate.set_opacity(0.5), moon.animate.set_opacity(0.3), run_time=4 ) # ============================================================================ # MAIN JOURNEY - FULL COMPOSITION # ============================================================================ class SuryaJourney(Scene): """ SURYA — The Complete Journey Through Feeling 14 tracks of mathematical beauty """ def construct(self): # Persistent elements self.soul = SoulOrb(color=WHITE, radius=0.3) self.stars = self.create_stars() self.particles = self.create_particles() # Journey begins self.intro() self.track_01_skin() self.track_02_u_saved_me() self.track_03_nothing() self.track_04_sweet_relief() self.track_05_tiptoe() self.track_06_natures_call() self.track_07_dreamcatcher() self.track_08_idk() self.track_09_with_u() self.track_10_poor_you_poor_me() self.track_11_wait_4_u() self.track_12_run_to_u() self.track_13_medications() self.track_14_hollow() self.finale() def create_stars(self): stars = VGroup() for _ in range(100): star = Dot( point=[random.uniform(-7, 7), random.uniform(-4, 4), 0], radius=random.uniform(0.01, 0.05), color=WHITE ) star.set_opacity(0) stars.add(star) return stars def create_particles(self): particles = VGroup() for _ in range(60): p = Dot( point=[random.uniform(-7, 7), random.uniform(-5, -4), 0], radius=random.uniform(0.02, 0.05), color=WHITE ) p.set_opacity(0) particles.add(p) return particles def transition_color(self, new_color, run_time=2): """Smoothly transition soul and ambient elements to new color""" new_soul = SoulOrb(color=new_color, radius=self.soul.core.radius * 5) new_soul.move_to(self.soul.get_center()) self.play( Transform(self.soul, new_soul), run_time=run_time ) def show_title(self, number, title, lyric="", color=WHITE): """Display track title""" num_text = Text(f"{number:02d}", font_size=24, color=color) num_text.set_opacity(0.4) num_text.to_edge(UP, buff=1) title_text = Text(title, font_size=72, color=color, slant=ITALIC) title_text.next_to(num_text, DOWN, buff=0.5) lyric_text = Text(lyric, font_size=28, color=color, slant=ITALIC) lyric_text.set_opacity(0.6) lyric_text.next_to(title_text, DOWN, buff=0.5) group = VGroup(num_text, title_text, lyric_text) self.play( FadeIn(group, shift=UP * 0.5), run_time=1.5 ) self.wait(1) self.play( FadeOut(group, shift=UP * 0.5), run_time=1 ) # =========== INTRO =========== def intro(self): # Title sequence surya_text = Text("SURYA", font_size=120, color=WHITE) sub_text = Text("a journey through feeling", font_size=32, color=WHITE) sub_text.set_opacity(0.5) sub_text.next_to(surya_text, DOWN, buff=0.5) artist_text = Text("DAS", font_size=20, color=WHITE) artist_text.set_opacity(0.3) artist_text.next_to(sub_text, DOWN, buff=1) self.play( FadeIn(surya_text, scale=0.9), run_time=3 ) self.play(FadeIn(sub_text, artist_text), run_time=2) self.wait(2) # Soul emerges self.add(self.stars, self.particles) self.play( FadeIn(self.soul, scale=0.5), FadeOut(surya_text, sub_text, artist_text), run_time=3 ) self.wait(1) # =========== TRACK 01: SKIN =========== def track_01_skin(self): color = SuryaColors.SKIN self.show_title(1, "skin", '"don\'t fit in my own skin"', color) # Transform soul color self.transition_color(color) # Morphing spirograph - identity struggle spiro1 = Spirograph(R=3, r=0.7, d=1.2, color=color) spiro2 = Spirograph(R=3, r=1.3, d=0.8, color=color) spiro1.scale(0.8) spiro2.scale(0.8) self.play(Create(spiro1), run_time=3) # Soul pulsates uncomfortably self.play( self.soul.animate.scale(0.7), run_time=1 ) self.play( self.soul.animate.scale(1.4), run_time=1 ) # Transform identity self.play( Transform(spiro1, spiro2), self.soul.animate.scale(0.8), run_time=4 ) # Particles of self floating temp_particles = ParticleField(40, color=color) self.play(FadeIn(temp_particles, lag_ratio=0.05), run_time=2) self.play( temp_particles.animate.shift(UP * 2).set_opacity(0), run_time=3 ) # Fade out self.play( FadeOut(spiro1, temp_particles), self.soul.animate.scale(0.8), run_time=2 ) # =========== TRACK 02: U SAVED ME =========== def track_02_u_saved_me(self): color = SuryaColors.SAVED self.show_title(2, "u saved me", '"you saved me from my broken soul"', color) # Soul fragments scattered fragments = VGroup(*[ Dot(point=[random.uniform(-2, 2), random.uniform(-2, 2), 0], radius=0.05, color=color) for _ in range(25) ]) self.play( FadeIn(fragments, lag_ratio=0.05), self.soul.animate.set_opacity(0.3), run_time=2 ) # Fragments coalesce self.play( *[f.animate.move_to(self.soul.get_center()) for f in fragments], run_time=3 ) self.transition_color(color) self.play( FadeOut(fragments), self.soul.animate.set_opacity(1).scale(1.3), run_time=2 ) # Sacred geometry - spiritual awakening flower = FlowerOfLife(rings=2, radius=0.6, color=color) flower.set_opacity(0) self.add(flower) # Hopeful spirograph spiro = Spirograph(R=4, r=1.5, d=2, color=color) spiro.scale(0.7) spiro.set_opacity(0) self.add(spiro) self.play( flower.animate.set_opacity(0.4), spiro.animate.set_opacity(0.5), run_time=4 ) # Harmony pulse self.play( self.soul.animate.scale(1.2), flower.animate.scale(1.1), run_time=1.5 ) self.play( self.soul.animate.scale(1/1.2), flower.animate.scale(1/1.1), run_time=1.5 ) self.play( FadeOut(flower, spiro), run_time=2 ) # =========== TRACK 03: NOTHING =========== def track_03_nothing(self): color = SuryaColors.NOTHING self.show_title(3, "nothing", '"I lost my heart, now I feel nothing"', color) self.transition_color(color) # Voronoi fragmentation voronoi = VoronoiFragments(num_points=25, color=color) self.play( self.soul.animate.scale(0.6), run_time=2 ) self.play(Create(voronoi), run_time=4) # Grey void grey_circle = Circle(radius=3, color=color) grey_circle.set_stroke(width=1, opacity=0.2) grey_circle.set_fill(color, opacity=0.03) self.play( FadeIn(grey_circle), self.soul.animate.scale(0.5).set_opacity(0.3), voronoi.animate.set_opacity(0.1), run_time=4 ) # Hollow pulsing for _ in range(2): self.play( grey_circle.animate.scale(1.1), run_time=1.5, rate_func=there_and_back ) self.wait(1) # Scatter into void self.play( FadeOut(voronoi, shift=UP), FadeOut(grey_circle), self.soul.animate.set_opacity(0.2), run_time=3 ) # =========== TRACK 04: SWEET RELIEF =========== def track_04_sweet_relief(self): color = SuryaColors.RELIEF self.show_title(4, "sweet relief", '"seeing ghosts around my throat"', color) self.transition_color(color) self.play(self.soul.animate.set_opacity(0.8).scale(1.5), run_time=1) # Ghost spirals ghosts = VGroup() for i in range(5): ghost = Spirograph(R=2 + i * 0.3, r=0.5, d=1 + i * 0.2, color=color) ghost.scale(0.5) ghost.set_opacity(0.15 + i * 0.05) ghost.rotate(i * PI / 5) ghosts.add(ghost) self.play( *[Create(g) for g in ghosts], run_time=4, lag_ratio=0.3 ) # Ghosts circle menacingly self.play( Rotate(ghosts, PI, about_point=ORIGIN), self.soul.animate.scale(0.8), run_time=4 ) # Soul struggles self.play(self.soul.animate.shift(UP * 0.3), run_time=0.4) self.play(self.soul.animate.shift(DOWN * 0.3), run_time=0.4) # Ghosts close in self.play( ghosts.animate.scale(0.7), run_time=3 ) # Brief relief self.play( ghosts.animate.scale(1.5).set_opacity(0.05), self.soul.animate.scale(1.2).set_opacity(1), run_time=2 ) self.play(FadeOut(ghosts), run_time=2) # =========== TRACK 05: TIPTOE =========== def track_05_tiptoe(self): color = SuryaColors.RELIEF self.show_title(5, "tiptoe", "", color) # Lissajous path path = LissajousCurve(a=3, b=2, delta=PI/4, color=color) path.set_opacity(0.3) self.play(Create(path), run_time=2) # Careful movement self.soul.move_to(LEFT * 3) positions = [LEFT * 2, LEFT * 1, ORIGIN, RIGHT * 1, RIGHT * 2] for pos in positions: self.play( self.soul.animate.move_to(pos), run_time=0.8 ) self.wait(0.2) # Tension path path2 = LissajousCurve(a=5, b=4, delta=PI/3, color=color) path2.set_opacity(0.2) self.play( Transform(path, path2), self.soul.animate.move_to(ORIGIN).scale(0.8), run_time=3 ) self.play(FadeOut(path), run_time=1) # =========== TRACK 06: NATURE'S CALL =========== def track_06_natures_call(self): color = SuryaColors.NATURE self.show_title(6, "nature's call", '"thank you for joining us"', color) self.transition_color(color) self.play(self.soul.animate.scale(1.3), run_time=1) # Fractal tree grows tree = FractalTree(depth=6, length=1.5, color=color) tree.shift(DOWN * 2) tree.set_opacity(0) self.add(tree) self.play( tree.animate.set_opacity(0.5), run_time=5 ) # Nature particles float up nature_particles = VGroup() for _ in range(40): p = Dot( point=[random.uniform(-4, 4), random.uniform(-3, -2), 0], radius=random.uniform(0.02, 0.05), color=color ) p.set_opacity(random.uniform(0.3, 0.6)) nature_particles.add(p) self.play(FadeIn(nature_particles, lag_ratio=0.03), run_time=2) self.play( *[p.animate.shift(UP * random.uniform(4, 6)) for p in nature_particles], run_time=5 ) # Golden spiral - nature's math spiral = GoldenSpiral(turns=3, color=color) spiral.scale(0.3) spiral.set_opacity(0) self.play( spiral.animate.set_opacity(0.5).scale(2), run_time=4 ) self.play( FadeOut(tree, spiral, nature_particles), run_time=2 ) # =========== TRACK 07: DREAMCATCHER =========== def track_07_dreamcatcher(self): color = SuryaColors.DREAM self.show_title(7, "dreamcatcher", '"falling through the cracks"', color) self.transition_color(color) self.soul.move_to(UP * 2.5) # Dreamcatcher web web = VGroup() for i in range(6): angle = i * PI / 3 line = Line(ORIGIN, 3 * np.array([np.cos(angle), np.sin(angle), 0])) line.set_stroke(color, width=1, opacity=0.4) web.add(line) for r in [0.5, 1, 1.5, 2, 2.5]: circle = Circle(radius=r, color=color) circle.set_stroke(width=1, opacity=0.3) web.add(circle) self.play(Create(web), run_time=3) # Soul falls through self.play( self.soul.animate.shift(DOWN * 2), run_time=2, rate_func=rate_functions.ease_in_quad ) # Passing through layers for _ in range(2): self.play( web.animate.scale(1.1).set_opacity(0.2), run_time=0.5 ) self.play( web.animate.scale(1/1.1).set_opacity(0.4), run_time=0.5 ) self.play( self.soul.animate.shift(DOWN * 1.2), run_time=1.5 ) # Falls through completely self.play( self.soul.animate.move_to(ORIGIN).scale(0.7).set_opacity(0.5), web.animate.set_opacity(0.1), run_time=3 ) self.play(FadeOut(web), run_time=1) # =========== TRACK 08: IDK =========== def track_08_idk(self): color = SuryaColors.IDK self.show_title(8, "idk", '"drugs don\'t work on me no more"', color) self.transition_color(color) self.play(self.soul.animate.set_opacity(0.7).scale(1.2), run_time=1) # Strange attractor - chaos attractor = StrangeAttractor(color=color) attractor.scale(0.5) self.play(Create(attractor), run_time=4) # Erratic wandering for _ in range(6): point = np.array([random.uniform(-1.5, 1.5), random.uniform(-1, 1), 0]) self.play( self.soul.animate.move_to(point), run_time=0.5 ) # Multiple confused curves curves = VGroup() for i in range(3): curve = LissajousCurve( a=random.randint(2, 5), b=random.randint(2, 5), delta=random.uniform(0, PI), color=color ) curve.scale(0.5 + i * 0.2) curve.set_opacity(0.2) curves.add(curve) self.play( *[Create(c) for c in curves], run_time=3, lag_ratio=0.2 ) # Spin in confusion self.play( Rotate(curves, PI, about_point=ORIGIN), self.soul.animate.move_to(ORIGIN).scale(0.8), run_time=4 ) # Collapse self.play( FadeOut(attractor, curves), self.soul.animate.scale(0.7).set_opacity(0.5), run_time=3 ) # =========== TRACK 09: WITH U (THE TURN) =========== def track_09_with_u(self): color = SuryaColors.WITH_U self.show_title(9, "with u", '"floating through the stars"', color) # This is THE TURN - second soul appears self.play(self.soul.animate.shift(LEFT * 2).set_opacity(1).scale(1.3), run_time=2) self.transition_color(WHITE) # Stars light up self.play( *[s.animate.set_opacity(random.uniform(0.3, 0.9)) for s in self.stars], run_time=3, lag_ratio=0.01 ) # Second soul emerges - golden soul2 = SoulOrb(color=color, radius=0.25) soul2.shift(RIGHT * 5) soul2.set_opacity(0) self.add(soul2) self.play( soul2.animate.set_opacity(1).shift(LEFT * 3), run_time=3 ) # Souls approach each other self.play( self.soul.animate.shift(RIGHT * 0.5), soul2.animate.shift(LEFT * 0.5), run_time=2 ) # Golden spiral between them orbit_center = (self.soul.get_center() + soul2.get_center()) / 2 spiral = GoldenSpiral(turns=4, color=color) spiral.scale(0.4) spiral.move_to(orbit_center) spiral.set_opacity(0) self.play(spiral.animate.set_opacity(0.6), run_time=2) # Binary orbit for _ in range(2): self.play( Rotate(self.soul, PI, about_point=orbit_center), Rotate(soul2, PI, about_point=orbit_center), Rotate(spiral, PI/2, about_point=orbit_center), run_time=4 ) # Closer, colors blend self.play( self.soul.animate.scale(1.2).move_to(orbit_center + LEFT * 0.3), soul2.animate.scale(1.2).move_to(orbit_center + RIGHT * 0.3), spiral.animate.scale(1.5), run_time=3 ) # Sacred geometry climax flower = FlowerOfLife(rings=2, radius=0.5, color=color) flower.move_to(orbit_center) flower.set_opacity(0) self.play( flower.animate.set_opacity(0.4).scale(1.2), self.stars.animate.set_opacity(0.9), run_time=3 ) # Peak pulse self.play( self.soul.animate.scale(1.3), soul2.animate.scale(1.3), flower.animate.scale(1.3), run_time=1.5 ) self.play( self.soul.animate.scale(1/1.3), soul2.animate.scale(1/1.3), flower.animate.scale(1/1.3), run_time=1.5 ) # Store soul2 for later self.soul2 = soul2 self.play( flower.animate.set_opacity(0.1), spiral.animate.set_opacity(0.2), run_time=2 ) self.play(FadeOut(flower, spiral), run_time=1) # =========== TRACK 10: POOR YOU POOR ME =========== def track_10_poor_you_poor_me(self): color = SuryaColors.POOR self.show_title(10, "poor you poor me", '"you left your cardigan on my bed"', color) self.transition_color(color) # Bittersweet spirograph spiro = Spirograph(R=3, r=1.8, d=1.5, color=color) spiro.scale(0.6) spiro.set_opacity(0.4) self.play(Create(spiro), run_time=3) # One soul drifts away self.play( self.soul2.animate.shift(RIGHT * 3).set_opacity(0.4), run_time=4 ) # Memories drift memories = VGroup() for _ in range(20): m = Dot( point=self.soul2.get_center() + np.array([ random.uniform(-0.5, 0.5), random.uniform(-0.5, 0.5), 0 ]), radius=0.03, color=SuryaColors.WITH_U ) m.set_opacity(0.5) memories.add(m) self.play(FadeIn(memories), run_time=1) self.play( *[m.animate.move_to( self.soul.get_center() + np.array([random.uniform(-0.3, 0.3), random.uniform(-0.3, 0.3), 0]) ) for m in memories], self.soul2.animate.shift(RIGHT * 2).set_opacity(0.1), run_time=4 ) # Bittersweet pulse self.play( self.soul.animate.scale(1.2), spiro.animate.set_opacity(0.6), run_time=2 ) self.play( self.soul.animate.scale(1/1.2), spiro.animate.set_opacity(0.3), run_time=2 ) self.play( FadeOut(self.soul2, memories, spiro), run_time=2 ) # =========== TRACK 11: WAIT 4 U =========== def track_11_wait_4_u(self): color = SuryaColors.WAIT self.show_title(11, "wait 4 u", "", color) self.transition_color(color) self.soul.move_to(ORIGIN) # Concentric circles - time passing circles = VGroup() for i in range(8): c = Circle(radius=0.5 + i * 0.4, color=color) c.set_stroke(width=1, opacity=0.3 - i * 0.03) circles.add(c) self.play( *[Create(c) for c in circles], run_time=3, lag_ratio=0.3 ) # Patient pulsing for _ in range(2): self.play( circles.animate.scale(1.1), self.soul.animate.scale(0.9), run_time=2 ) self.play( circles.animate.scale(1/1.1), self.soul.animate.scale(1/0.9), run_time=2 ) # Longing spiral spiral = GoldenSpiral(turns=5, color=color) spiral.scale(0.3) spiral.set_opacity(0) self.play( spiral.animate.set_opacity(0.4).scale(2), circles.animate.set_opacity(0.1), run_time=4 ) self.play(FadeOut(circles, spiral), run_time=2) # =========== TRACK 12: RUN TO U =========== def track_12_run_to_u(self): color = SuryaColors.RUN self.show_title(12, "run to u", '"if the sky was falling I would run to you"', color) self.transition_color(color) self.soul.move_to(LEFT * 4) # Target in distance target = SoulOrb(color=SuryaColors.WITH_U, radius=0.25) target.shift(RIGHT * 4) target.set_opacity(0.3) self.add(target) # Speed lines speed_lines = VGroup() for _ in range(15): y = random.uniform(-3, 3) line = Line(LEFT * 7, RIGHT * 7, color=color) line.shift(UP * y) line.set_stroke(width=1, opacity=0.2) speed_lines.add(line) self.play(FadeIn(speed_lines), run_time=0.5) # Urgent run self.play( self.soul.animate.shift(RIGHT * 4), target.animate.set_opacity(0.7), run_time=2, rate_func=rate_functions.ease_in_quad ) # Final push self.play( self.soul.animate.shift(RIGHT * 3), target.animate.shift(LEFT * 1).set_opacity(1), run_time=1.5, rate_func=rate_functions.ease_out_quad ) # Collision burst burst = VGroup() for i in range(12): angle = i * PI / 6 ray = Line(ORIGIN, 2 * np.array([np.cos(angle), np.sin(angle), 0])) ray.set_stroke(color, width=3, opacity=0.6) burst.add(ray) burst.move_to(RIGHT * 1.5) self.play( FadeIn(burst, scale=0.5), self.soul.animate.move_to(RIGHT * 1.5).scale(1.2), target.animate.move_to(RIGHT * 1.5).scale(1.2), run_time=1 ) self.play( burst.animate.scale(2).set_opacity(0), FadeOut(speed_lines, target), run_time=2 ) self.remove(burst) # =========== TRACK 13: MEDICATIONS =========== def track_13_medications(self): color = SuryaColors.MEDS self.show_title(13, "medications", '"raging in my head"', color) self.transition_color(color) self.soul.move_to(ORIGIN) # Chaos attractor attractor = StrangeAttractor(color=color) attractor.scale(0.5) self.play(Create(attractor), run_time=3) # Aggressive spirographs spiros = VGroup() for i in range(3): s = Spirograph(R=2 + i, r=0.5 + i * 0.3, d=1.5, color=color) s.scale(0.4) s.set_opacity(0.3) s.rotate(i * PI / 3) spiros.add(s) self.play( *[Create(s) for s in spiros], run_time=2 ) # Soul shakes original_pos = self.soul.get_center() for _ in range(5): offset = np.array([random.uniform(-0.3, 0.3), random.uniform(-0.3, 0.3), 0]) self.play( self.soul.animate.move_to(original_pos + offset), run_time=0.1 ) self.play(self.soul.animate.move_to(original_pos), run_time=0.2) # Red pulses for _ in range(2): pulse = Circle(radius=0.5, color=color) pulse.set_stroke(width=3, opacity=0.8) self.add(pulse) self.play( pulse.animate.scale(4).set_opacity(0), spiros.animate.rotate(PI/6), run_time=1 ) self.remove(pulse) # Struggle self.play( Rotate(attractor, PI/2, about_point=ORIGIN), spiros.animate.set_opacity(0.5), self.soul.animate.scale(0.8), run_time=3 ) # Exhaustion self.play( attractor.animate.set_opacity(0.2), spiros.animate.set_opacity(0.1), self.soul.animate.scale(0.8).set_opacity(0.6), run_time=3 ) self.play(FadeOut(attractor, spiros), run_time=2) # =========== TRACK 14: HOLLOW =========== def track_14_hollow(self): color = SuryaColors.HOLLOW self.show_title(14, "hollow", '"you took my sorrow and flew it to the moon"', color) self.transition_color(color) self.play(self.soul.animate.move_to(ORIGIN).scale(1.3).set_opacity(1), run_time=2) # Stars return bright self.play( *[s.animate.set_opacity(random.uniform(0.4, 0.9)) for s in self.stars], run_time=3, lag_ratio=0.01 ) # Golden spiral - resolution spiral = GoldenSpiral(turns=5, color=color) spiral.scale(0.2) spiral.set_opacity(0) self.play( spiral.animate.set_opacity(0.6).scale(3), run_time=5 ) # Moon appears moon = Circle(radius=1.5, color=color) moon.set_fill(color, opacity=0.1) moon.set_stroke(color, width=2, opacity=0.5) moon.shift(UP * 2 + RIGHT * 3) self.play(FadeIn(moon, scale=0.5), run_time=3) # Sorrow flies to moon sorrow = VGroup() for _ in range(15): s = Dot( point=self.soul.get_center() + np.array([ random.uniform(-0.4, 0.4), random.uniform(-0.4, 0.4), 0 ]), radius=0.04, color=GREY ) sorrow.add(s) self.play(FadeIn(sorrow), run_time=1) self.play( *[s.animate.move_to(moon.get_center() + np.array([ random.uniform(-0.4, 0.4), random.uniform(-0.4, 0.4), 0 ])).set_opacity(0) for s in sorrow], self.soul.animate.scale(1.3).set_opacity(1), run_time=4 ) # Sacred geometry finale flower = FlowerOfLife(rings=2, radius=0.6, color=color) flower.set_opacity(0) self.play( flower.animate.set_opacity(0.4), spiral.animate.set_opacity(0.8), run_time=3 ) # Final radiance self.play( self.soul.animate.scale(1.5), flower.animate.scale(1.3), spiral.animate.scale(1.2), self.stars.animate.set_opacity(1), run_time=2 ) self.wait(2) # Store for finale self.flower = flower self.spiral = spiral self.moon = moon # =========== FINALE =========== def finale(self): # Final title finale_text = Text("ready to feel something?", font_size=48, color=SuryaColors.HOLLOW, slant=ITALIC) finale_text.shift(DOWN * 1) finale_text.set_opacity(0) self.play( finale_text.animate.set_opacity(0.8), self.soul.animate.scale(1.2), run_time=3 ) self.wait(2) # Gentle fade self.play( self.soul.animate.scale(2).set_opacity(0.3), self.flower.animate.set_opacity(0.1), self.spiral.animate.set_opacity(0.2), self.stars.animate.set_opacity(0.4), self.moon.animate.set_opacity(0.2), finale_text.animate.set_opacity(0.4), run_time=4 ) # SURYA text returns surya_final = Text("SURYA", font_size=80, color=SuryaColors.HOLLOW) surya_final.set_opacity(0) surya_final.shift(UP * 1) das_final = Text("DAS", font_size=24, color=WHITE) das_final.set_opacity(0) das_final.next_to(surya_final, DOWN, buff=0.5) self.play( surya_final.animate.set_opacity(0.6), das_final.animate.set_opacity(0.3), finale_text.animate.shift(DOWN * 0.5).set_opacity(0.2), run_time=3 ) self.wait(3) # Final fade to black self.play( *[mob.animate.set_opacity(0) for mob in self.mobjects], run_time=4 ) self.wait(1) # ============================================================================ # INDIVIDUAL TRACK SCENES (for testing) # ============================================================================ class TestSoul(Scene): """Quick test of soul orb""" def construct(self): soul = SoulOrb(color=SuryaColors.WITH_U, radius=0.3) self.play(FadeIn(soul, scale=0.5), run_time=2) for _ in range(3): self.play(soul.animate.scale(1.3), run_time=1) self.play(soul.animate.scale(1/1.3), run_time=1) self.wait(1) class TestMathObjects(Scene): """Test mathematical objects""" def construct(self): # Spirograph spiro = Spirograph(R=3, r=1, d=1.5, color=PINK) spiro.scale(0.5) self.play(Create(spiro), run_time=3) self.wait(1) # Golden spiral spiral = GoldenSpiral(turns=4, color=GOLD) spiral.scale(0.5) self.play(Transform(spiro, spiral), run_time=2) self.wait(1) # Flower of life flower = FlowerOfLife(rings=2, radius=0.5, color=TEAL) self.play(FadeIn(flower), run_time=2) self.wait(1) if __name__ == "__main__": print("SURYA — A Mathematical Journey Through Feeling") print("Render with: manim -pqh --fps 60 surya_journey.py SuryaJourney") print("Preview with: manim -pql surya_journey.py SuryaJourney")