from manim import * import numpy as np import random class OSKVLogo3D(ThreeDScene): def construct(self): self.camera.background_color = "#050510" # === PART 1: 3D Camera Sweep with Rotating Geometry === self.set_camera_orientation(phi=70 * DEGREES, theta=-45 * DEGREES) # Wireframe sphere sphere_wireframe = Surface( lambda u, v: np.array([ 2 * np.cos(u) * np.sin(v), 2 * np.sin(u) * np.sin(v), 2 * np.cos(v) ]), u_range=[0, TAU], v_range=[0, PI], resolution=(12, 6), fill_opacity=0.05, stroke_width=1, stroke_color=BLUE_B, stroke_opacity=0.6 ) # Inner sphere inner_sphere = Surface( lambda u, v: np.array([ 0.8 * np.cos(u) * np.sin(v), 0.8 * np.sin(u) * np.sin(v), 0.8 * np.cos(v) ]), u_range=[0, TAU], v_range=[0, PI], resolution=(8, 4), fill_opacity=0.1, fill_color=PURPLE, stroke_width=0.5, stroke_color=PURPLE_B, stroke_opacity=0.4 ) # Torus rings torus = Surface( lambda u, v: np.array([ (2.5 + 0.12 * np.cos(v)) * np.cos(u), (2.5 + 0.12 * np.cos(v)) * np.sin(u), 0.12 * np.sin(v) ]), u_range=[0, TAU], v_range=[0, TAU], resolution=(24, 6), fill_opacity=0.3, fill_color=TEAL, stroke_width=0.5, stroke_color=TEAL, stroke_opacity=0.5 ) torus2 = Surface( lambda u, v: np.array([ 0.12 * np.sin(v), (2.5 + 0.12 * np.cos(v)) * np.cos(u), (2.5 + 0.12 * np.cos(v)) * np.sin(u), ]), u_range=[0, TAU], v_range=[0, TAU], resolution=(24, 6), fill_opacity=0.3, fill_color=BLUE, stroke_width=0.5, stroke_color=BLUE, stroke_opacity=0.5 ) # 3D floating dots dots_3d = VGroup() for _ in range(40): r = random.uniform(3, 5) theta_r = random.uniform(0, TAU) phi_r = random.uniform(0, PI) dot = Dot3D( point=np.array([ r * np.sin(phi_r) * np.cos(theta_r), r * np.sin(phi_r) * np.sin(theta_r), r * np.cos(phi_r) ]), radius=random.uniform(0.03, 0.07), color=random.choice([BLUE, PURPLE, TEAL, WHITE]) ) dot.set_opacity(random.uniform(0.3, 0.7)) dots_3d.add(dot) # Build scene self.play(Create(sphere_wireframe), run_time=1.5) self.play( Create(inner_sphere), FadeIn(dots_3d), run_time=1 ) self.play(Create(torus), Create(torus2), run_time=1.5) self.move_camera(theta=-20 * DEGREES, phi=60 * DEGREES, run_time=1) # Rotate everything all_3d = VGroup(sphere_wireframe, inner_sphere, torus, torus2, dots_3d) self.play(Rotate(all_3d, PI/3, axis=UP), run_time=1.5) self.move_camera(theta=30 * DEGREES, phi=50 * DEGREES, run_time=1) # === PART 2: Collapse to 2D === self.play(all_3d.animate.scale(0.3).set_opacity(0.15), run_time=1) self.move_camera(theta=0, phi=0, run_time=0.8) # Flash flash = Rectangle(width=20, height=12, fill_color=WHITE, fill_opacity=0.7, stroke_width=0) self.play(FadeIn(flash, run_time=0.15)) self.play(FadeOut(flash, run_time=0.3), FadeOut(all_3d, run_time=0.3)) # === PART 3: Logo reveal === # Since ImageMobject can be tricky in 3D, use it after camera is face-on logo = ImageMobject("/Users/jakeshore/.clawdbot/workspace/oskv_logo.png") logo.scale_to_fit_width(7) self.play(FadeIn(logo), run_time=0.8) # === PART 4: 3D cube wireframe around logo === cube_size = 4.5 vertices = [ np.array([x, y, z]) * cube_size / 2 for x in [-1, 1] for y in [-1, 1] for z in [-1, 1] ] edges_idx = [ (0,1),(0,2),(0,4),(1,3),(1,5),(2,3), (2,6),(3,7),(4,5),(4,6),(5,7),(6,7) ] cube_edges = VGroup() for i, j in edges_idx: line = Line3D(start=vertices[i], end=vertices[j], thickness=0.01, color=BLUE_B) line.set_opacity(0.4) cube_edges.add(line) vertex_dots = VGroup() for v in vertices: dot = Dot3D(point=v, radius=0.06, color=TEAL) dot.set_opacity(0.7) vertex_dots.add(dot) cube_group = VGroup(cube_edges, vertex_dots) self.play( LaggedStart(*[Create(e) for e in cube_edges], lag_ratio=0.05), LaggedStart(*[GrowFromCenter(d) for d in vertex_dots], lag_ratio=0.05), run_time=1.5 ) # Rotate cube self.play( Rotate(cube_group, PI/4, axis=UP + RIGHT * 0.5), run_time=2 ) # === PART 5: Orbiting parametric paths === orbit_ring = ParametricFunction( lambda t: np.array([5 * np.cos(t), 1.5 * np.sin(t), 0.8 * np.sin(t)]), t_range=[0, TAU], color=PURPLE, stroke_width=2, stroke_opacity=0.6 ) orbit_ring2 = ParametricFunction( lambda t: np.array([5 * np.cos(t), -0.8 * np.sin(t), 1.5 * np.sin(t)]), t_range=[0, TAU], color=TEAL, stroke_width=2, stroke_opacity=0.5 ) self.play(Create(orbit_ring), Create(orbit_ring2), run_time=1) # Energy dots energy_dots = VGroup() for i in range(4): t = i * TAU / 4 dot = Dot3D( point=np.array([5*np.cos(t), 1.5*np.sin(t), 0.8*np.sin(t)]), radius=0.08, color=PURPLE ) energy_dots.add(dot) energy_dots2 = VGroup() for i in range(4): t = i * TAU / 4 dot = Dot3D( point=np.array([5*np.cos(t), -0.8*np.sin(t), 1.5*np.sin(t)]), radius=0.08, color=TEAL ) energy_dots2.add(dot) self.play(FadeIn(energy_dots), FadeIn(energy_dots2), run_time=0.3) # Rotate energy + cube self.play( Rotate(energy_dots, PI/2, about_point=ORIGIN, axis=OUT), Rotate(energy_dots2, PI/2, about_point=ORIGIN, axis=UP), Rotate(cube_group, PI/6, axis=UP), run_time=1.5 ) # === PART 6: Pulse === self.play( cube_group.animate.scale(1.1), rate_func=there_and_back, run_time=0.7 ) # Ring wave ring3d = ParametricFunction( lambda t: np.array([0.5*np.cos(t), 0.5*np.sin(t), 0]), t_range=[0, TAU], color=WHITE, stroke_width=3, stroke_opacity=0.8 ) self.add(ring3d) self.play( ring3d.animate.scale(15).set_stroke(opacity=0), run_time=0.8 ) self.remove(ring3d) # Final slow rotation self.play( Rotate(cube_group, PI/8, axis=UP + OUT * 0.3), Rotate(energy_dots, PI/4, about_point=ORIGIN, axis=OUT), Rotate(energy_dots2, PI/4, about_point=ORIGIN, axis=UP), run_time=2 ) self.wait(1) # Fade out everything = VGroup(cube_group, orbit_ring, orbit_ring2, energy_dots, energy_dots2) self.play( FadeOut(everything), FadeOut(logo), run_time=1.5 )