Skip to content

Instantly share code, notes, and snippets.

@bmorphism
Created November 3, 2024 04:32
Show Gist options
  • Save bmorphism/0b82ada6b6f0ae9d79426769c14c6dd6 to your computer and use it in GitHub Desktop.
Save bmorphism/0b82ada6b6f0ae9d79426769c14c6dd6 to your computer and use it in GitHub Desktop.
txt2world
from manim import *
from manim.utils.space_ops import rotate_vector
from manim.utils.color import interpolate_color
import numpy as np
class CreateCircle(Scene):
def construct(self):
circle = Circle() # create a circle
circle.set_fill(PINK, opacity=0.5) # set the color and transparency
self.play(Create(circle)) # show the circle on screen
class SquareToCircle(Scene):
def construct(self):
circle = Circle() # create a circle
circle.set_fill(PINK, opacity=0.5) # set color and transparency
square = Square() # create a square
square.rotate(PI / 4) # rotate a certain amount
self.play(Create(square)) # animate the creation of the square
self.play(Transform(square, circle)) # interpolate the square into the circle
self.play(FadeOut(square)) # fade out animation
class SquareAndCircle(Scene):
def construct(self):
circle = Circle() # create a circle
circle.set_fill(PINK, opacity=0.5) # set the color and transparency
square = Square() # create a square
square.set_fill(BLUE, opacity=0.5) # set the color and transparency
square.next_to(circle, RIGHT, buff=0.5) # set the position
self.play(Create(circle), Create(square)) # show the shapes on screen
class HolographicPrinciple(Scene):
def construct(self):
def fractal_tree(start_point, direction, length, depth):
if depth == 0 or length < 0.05:
return VGroup()
end_point = start_point + length * direction
line = Line(start_point, end_point, color=GREEN)
left_branch = fractal_tree(
end_point,
rotate_vector(direction, PI / 6),
length * 0.67,
depth - 1
)
right_branch = fractal_tree(
end_point,
rotate_vector(direction, -PI / 6),
length * 0.67,
depth - 1
)
return VGroup(line, left_branch, right_branch)
tree = fractal_tree(ORIGIN + DOWN * 3, UP, 1.5, 8)
self.play(Create(tree))
self.wait()
class YoYo(Scene):
def construct(self):
# Create the yoyo (a circle) and the string
yoyo_radius = 0.3
yoyo = Circle(radius=yoyo_radius, color=RED, fill_opacity=1)
yoyo_initial_position = UP * 2
yoyo.move_to(yoyo_initial_position)
string = Line(ORIGIN, yoyo.get_center(), color=WHITE)
self.add(string, yoyo)
# Define the path for the yoyo to move along
yoyo_path = Line(yoyo_initial_position, DOWN * 2)
# Updater to keep the string connected to the yoyo
def update_string(mob):
new_string = Line(ORIGIN, yoyo.get_center(), color=WHITE)
mob.become(new_string)
string.add_updater(update_string)
# Animate the yoyo going down and up repeatedly
self.play(
MoveAlongPath(yoyo, yoyo_path, rate_func=linear),
run_time=2
)
self.play(
MoveAlongPath(yoyo, yoyo_path, rate_func=lambda t: 1 - t),
run_time=2
)
self.wait()
# Remove the updater when done
string.remove_updater(update_string)
class FoldingSierpinski(ThreeDScene):
def construct(self):
# Create the initial triangle vertices
p1 = LEFT * 4 + DOWN * 2
p2 = RIGHT * 4 + DOWN * 2
p3 = UP * 4 + DOWN * 2
vertices = [p1, p2, p3]
# Function to create the Sierpinski triangle recursively
def sierpinski(order, vertices):
if order == 0:
triangle = Polygon(
*vertices,
fill_color=WHITE,
fill_opacity=1,
stroke_color=BLACK,
stroke_width=0.5
)
return triangle
else:
# Calculate midpoints of the sides
midpoints = [
(vertices[0] + vertices[1]) / 2,
(vertices[1] + vertices[2]) / 2,
(vertices[2] + vertices[0]) / 2
]
# Recursively create smaller triangles
return VGroup(
sierpinski(order - 1, [vertices[0], midpoints[0], midpoints[2]]),
sierpinski(order - 1, [midpoints[0], vertices[1], midpoints[1]]),
sierpinski(order - 1, [midpoints[2], midpoints[1], vertices[2]])
)
# Create the Sierpinski triangle of order 4
order = 4
sierpinski_triangle = sierpinski(order, vertices)
sierpinski_triangle.set_style(stroke_width=0)
sierpinski_triangle.set_color_by_gradient(BLUE, GREEN, YELLOW, RED)
self.add(sierpinski_triangle)
self.wait(1)
# Set up the camera
self.set_camera_orientation(phi=75 * DEGREES, theta=-45 * DEGREES)
# Level 1 triangles for folding
# Compute midpoints
midpoints = [
(vertices[0] + vertices[1]) / 2,
(vertices[1] + vertices[2]) / 2,
(vertices[2] + vertices[0]) / 2
]
# Create the outer triangles and the central triangle
t_outer = [
Polygon(vertices[0], midpoints[0], midpoints[2], fill_color=BLUE_E, fill_opacity=1, stroke_width=0.5),
Polygon(vertices[1], midpoints[1], midpoints[0], fill_color=GREEN_E, fill_opacity=1, stroke_width=0.5),
Polygon(vertices[2], midpoints[2], midpoints[1], fill_color=RED_E, fill_opacity=1, stroke_width=0.5)
]
t_center = Polygon(midpoints[0], midpoints[1], midpoints[2], fill_color=YELLOW_E, fill_opacity=1, stroke_width=0.5)
# Add the triangles to the scene
self.add(t_center, *t_outer)
self.wait(1)
# Remove the large Sierpinski triangle
self.remove(sierpinski_triangle)
# Define fold axes and points
fold_animations = []
fold_axes = []
about_points = []
for i in range(3):
# Edge of the central triangle corresponding to the fold
start = midpoints[i]
end = midpoints[(i + 1) % 3]
edge_vector = end - start
# Fold axis is perpendicular to the edge, pointing out of the plane
fold_axis = np.cross(edge_vector, OUT)
fold_axis = normalize(fold_axis)
# The fold happens about the edge of the central triangle
about_point = start
# Save axis and point for unfolding
fold_axes.append(fold_axis)
about_points.append(about_point)
# Create folding animation
fold_animations.append(
Rotate(
t_outer[i],
angle=PI,
axis=fold_axis,
about_point=about_point,
run_time=2
)
)
# Play the folding animations
self.play(*fold_animations)
self.wait(2)
# Unfolding animations (reverse the folding)
unfold_animations = []
for i in range(3):
unfold_animations.append(
Rotate(
t_outer[i],
angle=-PI,
axis=fold_axes[i],
about_point=about_points[i],
run_time=2
)
)
self.play(*unfold_animations)
self.wait(2)
# Rotate the camera to showcase the 3D effect
self.begin_ambient_camera_rotation(rate=0.2)
self.wait(5)
self.stop_ambient_camera_rotation()
self.wait(2)
from manim import *
import numpy as np
class FoucaultPendulum(ThreeDScene):
def construct(self):
# Set up camera orientation
self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)
# Pendulum parameters
length = 5 # Length of the pendulum
g = 9.8 # Acceleration due to gravity
omega = np.sqrt(g / length) # Angular frequency
rotation_rate = 0.1 # Rotation rate simulating Earth's rotation
# Create pivot point
pivot = Dot3D(ORIGIN, color=WHITE)
self.add(pivot)
# Create pendulum bob
bob_radius = 0.2
bob = Sphere(radius=bob_radius, color=RED).move_to([0, -length, 0])
# Create rod
rod = Line3D(pivot.get_center(), bob.get_center(), color=WHITE)
# Group bob and rod
pendulum = VGroup(rod, bob)
self.add(pendulum)
# Create a reference circle (floor)
floor_radius = 3
floor = Circle(radius=floor_radius, color=GRAY)
floor.rotate(PI/2, axis=RIGHT)
floor.shift(DOWN * length)
self.add(floor)
# Add markers on the floor to show rotation
for angle in np.linspace(0, 2 * PI, 12, endpoint=False):
marker = Line(ORIGIN, RIGHT * 0.1, color=YELLOW)
marker.rotate(angle, axis=UP)
marker.shift([floor_radius * np.cos(angle), -length, floor_radius * np.sin(angle)])
self.add(marker)
# Initialize time for updater
pendulum.time = 0
# Animation updater
def update_pendulum(mob, dt):
mob.time += dt
angle = 0.2 * np.cos(omega * mob.time)
rotation = rotation_rate * mob.time
x = length * np.sin(angle) * np.cos(rotation)
y = -length * np.cos(angle)
z = length * np.sin(angle) * np.sin(rotation)
bob_position = np.array([x, y, z])
rod.put_start_and_end_on(pivot.get_center(), bob_position)
bob.move_to(bob_position)
pendulum.add_updater(update_pendulum)
# Ambient camera rotation for better visualization
self.begin_ambient_camera_rotation(rate=0.05)
# Run the animation
self.wait(20)
# Clean up
pendulum.remove_updater(update_pendulum)
self.stop_ambient_camera_rotation()
self.wait()
from manim import *
import numpy as np
class TropicalDerangementVisualization(Scene):
def construct(self):
# Display tropical operations using Text instead of MathTex
add_text = Text("Tropical Addition: a ⊕ b = min(a, b)", font_size=24).to_edge(UP)
mul_text = Text("Tropical Multiplication: a ⊗ b = a + b", font_size=24).next_to(add_text, DOWN)
self.play(Write(add_text), Write(mul_text))
self.wait(1)
# Create axes for tropical lines
axes = Axes(
x_range=[0, 6, 1],
y_range=[0, 6, 1],
x_length=6,
y_length=6,
axis_config={"include_numbers": True},
).shift(DOWN * 0.5)
axis_labels = axes.get_axis_labels(x_label="a", y_label="b")
self.play(Create(axes), Write(axis_labels))
self.wait(1)
# Plot tropical lines y = min(x, c)
c_values = [2, 4]
lines = VGroup()
colors = [BLUE, GREEN]
for c, color in zip(c_values, colors):
line = axes.plot_line_graph(
x_values=[0, c, 6],
y_values=[c, c, 6],
line_color=color
)
lines.add(line)
self.play(Create(lines))
self.wait(1)
# Visualize derangement
elements = ['1', '2', '3', '4']
positions = [LEFT * 3 + DOWN * 2, LEFT + DOWN * 2, RIGHT + DOWN * 2, RIGHT * 3 + DOWN * 2]
circles = VGroup(*[Circle(radius=0.5, color=WHITE).move_to(pos) for pos in positions])
labels = VGroup(*[Text(str(e), font_size=24).move_to(pos) for e, pos in zip(elements, positions)])
self.play(Create(circles), Write(labels))
self.wait(1)
# Derangement mapping
mapping = [2, 3, 4, 1] # A derangement permutation
arrows = VGroup()
for i, m in enumerate(mapping):
arrow = Arrow(
start=circles[i].get_right(),
end=circles[m - 1].get_right(),
buff=0.5,
color=YELLOW,
max_tip_length_to_length_ratio=0.1
)
arrows.add(arrow)
self.play(Create(arrows))
self.wait(1)
# Inverse derangement mapping
inverse_mapping = [4, 1, 2, 3]
inverse_arrows = VGroup()
for i, m in enumerate(inverse_mapping):
arrow = Arrow(
start=circles[i].get_left(),
end=circles[m - 1].get_left(),
buff=0.5,
color=RED,
max_tip_length_to_length_ratio=0.1
)
inverse_arrows.add(arrow)
self.play(Create(inverse_arrows))
self.wait(1)
# Transition to topological space visualization
self.play(
FadeOut(VGroup(add_text, mul_text, axes, axis_labels, lines, circles, labels, arrows, inverse_arrows))
)
self.wait(1)
# Visualize topological space (Torus)
torus = Torus(major_radius=2, minor_radius=0.7, color=GREY_BROWN)
torus.rotate(PI / 2, axis=RIGHT)
self.play(Create(torus))
self.wait(1)
# Animate path representing behaviors
dot = Dot(point=torus.point_at_angle(0), color=TEAL_A)
self.add(dot)
def update_dot(mob, dt):
mob.angle = (mob.angle + dt) % TAU
new_point = torus.point_at_angle(mob.angle)
mob.move_to(new_point)
dot.angle = 0
dot.add_updater(update_dot)
self.wait(10)
dot.remove_updater(update_dot)
self.wait(2)
from manim import *
import numpy as np
class MobiusStrip(ThreeDScene):
def construct(self):
# Set up camera orientation
self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)
# Parameters for the Möbius strip
radius = 2 # Radius of the central circle
width = 1 # Width of the strip
turns = 1 # Number of half-twists (1 for a standard Möbius strip)
# Create the Möbius strip
mobius = Surface(
lambda u, v: self.mobius_surface(u, v, radius, width, turns),
u_range=[0, TAU],
v_range=[-width / 2, width / 2],
checkerboard_colors=[BLUE_E, BLUE_D],
resolution=(50, 8)
)
# Add the Möbius strip to the scene
self.play(Create(mobius))
self.wait(1)
# Rotate the Möbius strip for visualization
self.play(Rotate(mobius, angle=TAU, axis=OUT), run_time=5)
self.wait(1)
def mobius_surface(self, u, v, radius, width, turns):
# Möbius strip parameterization
# u: angle around the circle
# v: position across the width of the strip
twist = turns * u / 2 # Controls the half-twist
x = (radius + v * np.cos(twist)) * np.cos(u)
y = (radius + v * np.cos(twist)) * np.sin(u)
z = v * np.sin(twist)
return np.array([x, y, z])
class TesseractProjection(ThreeDScene):
def construct(self):
# Set up camera orientation
self.set_camera_orientation(phi=75 * DEGREES, theta=45 * DEGREES)
# Parameters for the tesseract
size = 2 # Size of the hypercube
# Generate the vertices of a tesseract in 4D space
vertices_4d = []
for i in range(16):
x = size * (1 if i & 1 else -1)
y = size * (1 if i & 2 else -1)
z = size * (1 if i & 4 else -1)
w = size * (1 if i & 8 else -1)
vertices_4d.append([x, y, z, w])
# Project the 4D vertices into 3D space
projected_vertices = []
for v in vertices_4d:
# Perspective projection from 4D to 3D
d = 5 # Distance from viewer to the hypercube
w = v[3]
projection_factor = d / (d - w)
x = v[0] * projection_factor
y = v[1] * projection_factor
z = v[2] * projection_factor
projected_vertices.append([x, y, z])
# Create lines between vertices that are connected in 4D space
edges = []
for i in range(16):
for j in range(i + 1, 16):
# In 4D, vertices are connected if they differ by one coordinate
if bin(i ^ j).count('1') == 1:
start = projected_vertices[i]
end = projected_vertices[j]
edge = Line3D(
start=np.array(start),
end=np.array(end),
color=BLUE,
stroke_width=2,
)
edges.append(edge)
# Group all edges
tesseract = VGroup(*edges)
# Add axes for reference
axes = ThreeDAxes()
self.add(axes)
# Add the tesseract to the scene
self.play(Create(tesseract))
self.wait(1)
# Animate rotation of the tesseract
self.play(
Rotate(tesseract, angle=TAU, axis=OUT + RIGHT, run_time=8, rate_func=smooth)
)
self.wait(2)
from manim import *
import numpy as np
class ColoredTesseractProjection(ThreeDScene):
def construct(self):
# Set up camera orientation
self.set_camera_orientation(phi=75 * DEGREES, theta=45 * DEGREES)
# Parameters for the tesseract
size = 2 # Size of the hypercube
# Generate the vertices of a tesseract in 4D space
vertices_4d = []
for i in range(16):
x = size * (1 if i & 1 else -1)
y = size * (1 if i & 2 else -1)
z = size * (1 if i & 4 else -1)
w = size * (1 if i & 8 else -1)
vertices_4d.append([x, y, z, w])
# Project the 4D vertices into 3D space
projected_vertices = []
for v in vertices_4d:
# Perspective projection from 4D to 3D
d = 5 # Distance from viewer to the hypercube
w_coord = v[3]
projection_factor = d / (d - w_coord)
x = v[0] * projection_factor
y = v[1] * projection_factor
z = v[2] * projection_factor
projected_vertices.append([x, y, z])
# Create edges with coloring based on self-reflexive property
edges = VGroup()
for i in range(16):
for j in range(i + 1, 16):
# In 4D, vertices are connected if they differ by one coordinate
hamming_distance = bin(i ^ j).count('1')
if hamming_distance == 1:
start = projected_vertices[i]
end = projected_vertices[j]
# Assign color based on the coordinate that differs
differing_coordinate = int(np.log2(i ^ j))
if differing_coordinate == 0:
color = RED # x-coordinate differs
elif differing_coordinate == 1:
color = GREEN # y-coordinate differs
elif differing_coordinate == 2:
color = BLUE # z-coordinate differs
elif differing_coordinate == 3:
color = YELLOW # w-coordinate differs
edge = Line3D(
start=np.array(start),
end=np.array(end),
color=color,
stroke_width=2,
)
edges.add(edge)
# Add axes for reference
axes = ThreeDAxes()
self.add(axes)
# Add the tesseract edges to the scene
self.play(Create(edges))
self.wait(1)
# Animate rotation of the tesseract
self.play(
Rotate(edges, angle=TAU, axis=OUT + RIGHT, run_time=8, rate_func=smooth)
)
self.wait(2)
from manim import *
import numpy as np
class FiveDMobiusStrip(ThreeDScene):
def construct(self):
# Set up camera orientation
self.set_camera_orientation(phi=70 * DEGREES, theta=45 * DEGREES)
# Parameters for the Möbius strip
radius = 2 # Radius of the central circle
width = 1 # Width of the strip
twists = 1 # Number of half-twists
# Additional parameters to simulate higher dimensions
def five_d_mobius(u, v):
# Möbius strip parameterization extended to simulate higher dimensions
# u: angle around the central circle
# v: position across the width of the strip
# Simulating higher dimensions using extra sine and cosine functions
a = np.sin(2 * u + v)
b = np.cos(3 * u - v)
x = (radius + width * v * np.cos(twists * u / 2)) * np.cos(u) + 0.2 * a
y = (radius + width * v * np.cos(twists * u / 2)) * np.sin(u) + 0.2 * b
z = width * v * np.sin(twists * u / 2) + 0.2 * a * b
return np.array([x, y, z])
# Create the Möbius strip
mobius = Surface(
five_d_mobius,
u_range=[0, TAU],
v_range=[-1, 1],
resolution=(60, 16),
)
# Apply color mapping to simulate higher dimensions
mobius.set_color_by_rgb_function(
lambda x, y, z: (
0.5 * np.cos(2 * x) + 0.5,
0.5 * np.cos(2 * y) + 0.5,
0.5 * np.cos(2 * z) + 0.5
)
)
# Add the Möbius strip to the scene
self.add(mobius)
self.play(Create(mobius), run_time=3)
self.wait(1)
# Rotate the Möbius strip for visualization
self.play(
Rotate(mobius, angle=TAU, axis=OUT + RIGHT, run_time=8, rate_func=smooth)
)
self.wait(2)
from manim import *
import numpy as np
class AceToMobius(ThreeDScene):
def construct(self):
# Create the Ace of Spades using LaTeX
ace_of_spades = MathTex(r"A\spadesuit")
ace_of_spades.set_color(BLACK)
ace_of_spades.scale(3)
ace_of_spades.shift(UP * 0.5)
# Create the Möbius strip
mobius_strip = ParametricSurface(
self.mobius_function,
u_range=[0, TAU],
v_range=[-1, 1],
resolution=(50, 16),
checkerboard_colors=[GREY_BROWN, GREY_BROWN],
fill_opacity=1
)
mobius_strip.set_color(BLACK)
mobius_strip.scale(2)
# Set up the camera for 3D visualization
self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)
# Display the Ace of Spades
self.play(FadeIn(ace_of_spades))
self.wait(1)
# Transform the Ace into the Möbius strip
self.play(Transform(ace_of_spades, mobius_strip), run_time=4)
self.wait(1)
# Rotate the Möbius strip to showcase it
self.begin_ambient_camera_rotation(rate=0.2)
self.wait(5)
self.stop_ambient_camera_rotation()
self.wait(2)
def mobius_function(self, u, v):
# Möbius strip parameterization
x = (1 + 0.5 * v * np.cos(u / 2)) * np.cos(u)
y = (1 + 0.5 * v * np.cos(u / 2)) * np.sin(u)
z = 0.5 * v * np.sin(u / 2)
return np.array([x, y, z])
from manim import *
import numpy as np
class ColorfulBlochSphere(ThreeDScene):
def construct(self):
# Create the Bloch sphere
sphere = Sphere(radius=2, resolution=(50, 50))
sphere.set_fill(opacity=1)
sphere.set_color_by_gradient(RED, ORANGE, YELLOW, GREEN, BLUE, PURPLE)
sphere.set_stroke(color=WHITE, width=0.5)
# Create longitude and latitude lines
longitude_lines = VGroup()
latitude_lines = VGroup()
num_longitude = 24
num_latitude = 12
for i in range(num_longitude):
theta = TAU * i / num_longitude
lon_line = ParametricFunction(
lambda t: np.array([
2 * np.cos(t) * np.sin(theta),
2 * np.sin(t) * np.sin(theta),
2 * np.cos(theta)
]),
t_range=[0, TAU],
color=GREY_B,
stroke_width=0.5
)
longitude_lines.add(lon_line)
for i in range(1, num_latitude):
phi = PI * i / num_latitude
radius = 2 * np.sin(phi)
z = 2 * np.cos(phi)
lat_circle = Circle(radius=radius, color=GREY_B, stroke_width=0.5)
lat_circle.shift(z * OUT)
lat_circle.rotate(angle=90 * DEGREES, axis=RIGHT)
latitude_lines.add(lat_circle)
# Create axes
axes = ThreeDAxes(
x_range=[-2, 2, 1],
y_range=[-2, 2, 1],
z_range=[-2, 2, 1],
x_length=4,
y_length=4,
z_length=4,
)
# Label axes using Text instead of Tex
x_label = Text("X", color=RED).move_to([2.5, 0, 0])
y_label = Text("Y", color=GREEN).move_to([0, 2.5, 0])
z_label = Text("Z", color=BLUE).move_to([0, 0, 2.5])
labels = VGroup(x_label, y_label, z_label)
# Create a state vector
theta_angle = PI / 3 # Polar angle
phi_angle = PI / 4 # Azimuthal angle
vector = Arrow3D(
start=ORIGIN,
end=[
2 * np.sin(theta_angle) * np.cos(phi_angle),
2 * np.sin(theta_angle) * np.sin(phi_angle),
2 * np.cos(theta_angle)
],
color=YELLOW,
thickness=0.05,
)
# Animate the state vector rotating around the Bloch sphere
vector.rotate_about_origin(PI / 4)
# Set up camera
self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)
# Add all elements to the scene
self.add(axes, labels)
self.add(sphere)
self.add(longitude_lines, latitude_lines)
self.add(vector)
# Rotate the camera around the sphere
self.begin_ambient_camera_rotation(rate=0.1)
# Rotate the vector around the sphere
self.play(Rotate(vector, angle=TAU, axis=UP, about_point=ORIGIN, run_time=8, rate_func=linear))
self.wait()
from manim import *
import numpy as np
class ComplexSurfaces(ThreeDScene):
def construct(self):
# Set up the camera
self.set_camera_orientation(phi=60 * DEGREES, theta=-45 * DEGREES)
# Create the Kummer Surface approximation
kummer = self.create_kummer_surface()
kummer.set_color_by_gradient(BLUE, PURPLE)
kummer.scale(1.5)
# Create the Clebsch Diagonal Cubic approximation
clebsch = self.create_clebsch_cubic()
clebsch.set_color_by_gradient(RED, ORANGE)
clebsch.scale(1.5)
# Create the Steiner Surface approximation
steiner = self.create_steiner_surface()
steiner.set_color_by_gradient(GREEN, YELLOW)
steiner.scale(1.5)
# Create the Klein Bottle approximation
klein = self.create_klein_bottle()
klein.set_color_by_gradient(TEAL, PINK)
klein.scale(1.5)
# Transition between surfaces
self.add(kummer)
self.begin_ambient_camera_rotation(rate=0.1)
self.wait(2)
self.play(Transform(kummer, clebsch), run_time=3)
self.wait(2)
self.play(Transform(kummer, steiner), run_time=3)
self.wait(2)
self.play(Transform(kummer, klein), run_time=3)
self.wait(2)
self.play(FadeOut(kummer))
self.wait()
def create_kummer_surface(self):
# Approximate Kummer Surface
surface = Surface(
lambda u, v: self.kummer_parametric(u, v),
u_range=[-PI, PI],
v_range=[-PI, PI],
resolution=(48, 48),
checkerboard_colors=None,
fill_opacity=1,
stroke_color=WHITE,
stroke_width=0.5,
)
return surface
def kummer_parametric(self, u, v):
# Parametric equations for Kummer surface approximation
a = 1
x = a * np.cos(u) * np.cos(v)
y = a * np.sin(u) * np.cos(v)
z = a * np.sin(v)
return np.array([x, y, z])
def create_clebsch_cubic(self):
# Approximate Clebsch Diagonal Cubic
surface = Surface(
lambda u, v: self.clebsch_parametric(u, v),
u_range=[0, PI],
v_range=[0, TAU],
resolution=(48, 48),
checkerboard_colors=None,
fill_opacity=1,
stroke_color=WHITE,
stroke_width=0.5,
)
return surface
def clebsch_parametric(self, u, v):
# Parametric equations for Clebsch diagonal cubic approximation
a = 1
x = a * np.sin(u) * np.cos(v)
y = a * np.sin(u) * np.sin(v)
z = a * np.cos(u)
return np.array([x, y, z])
def create_steiner_surface(self):
# Approximate Steiner Surface (Roman Surface)
surface = Surface(
lambda u, v: self.steiner_parametric(u, v),
u_range=[0, PI],
v_range=[0, PI],
resolution=(48, 48),
checkerboard_colors=None,
fill_opacity=1,
stroke_color=WHITE,
stroke_width=0.5,
)
return surface
def steiner_parametric(self, u, v):
# Parametric equations for Steiner surface approximation
a = 1
x = a * np.sin(2 * u) * np.sin(v)
y = a * np.sin(2 * u) * np.cos(v)
z = a * np.cos(2 * u)
return np.array([x, y, z])
def create_klein_bottle(self):
# Approximate Klein Bottle
surface = Surface(
lambda u, v: self.klein_parametric(u, v),
u_range=[0, TAU],
v_range=[0, TAU],
resolution=(48, 48),
checkerboard_colors=None,
fill_opacity=1,
stroke_color=WHITE,
stroke_width=0.5,
)
return surface
def klein_parametric(self, u, v):
# Parametric equations for Klein bottle approximation
r = 2
x = (r + np.cos(u / 2) * np.sin(v) - np.sin(u / 2) * np.sin(2 * v)) * np.cos(u)
y = (r + np.cos(u / 2) * np.sin(v) - np.sin(u / 2) * np.sin(2 * v)) * np.sin(u)
z = np.sin(u / 2) * np.sin(v) + np.cos(u / 2) * np.sin(2 * v)
return np.array([x, y, z])
from manim import *
import numpy as np
class MobiusInsideTorus(ThreeDScene):
def construct(self):
# Set up the initial camera orientation
self.set_camera_orientation(phi=75 * DEGREES, theta=45 * DEGREES)
# Create the Torus
torus = Surface(
lambda u, v: self.torus_func(u, v),
u_range=[0, TAU],
v_range=[0, TAU],
resolution=(100, 100),
fill_opacity=0.5,
stroke_color=WHITE,
stroke_width=0.5,
)
torus.set(color_by_rgb_func=self.hyperbolic_color_func)
# Create the Möbius Strip
mobius_strip = Surface(
lambda u, v: self.mobius_func(u, v),
u_range=[0, TAU],
v_range=[-1, 1],
resolution=(100, 30),
fill_opacity=1,
stroke_color=WHITE,
stroke_width=0.5,
)
mobius_strip.set(color_by_rgb_func=self.hyperbolic_color_func)
# Add surfaces to the scene
self.add(torus, mobius_strip)
self.wait(1)
# Animate camera rotation by updating theta
self.play(
Rotate(
self.camera.gamma_tracker,
angle=360 * DEGREES,
run_time=8,
rate_func=linear
)
)
self.wait(1)
def torus_func(self, u, v):
# Parametric equations for a torus
R = 3 # Major radius
r = 1 # Minor radius
x = (R + r * np.cos(v)) * np.cos(u)
y = (R + r * np.cos(v)) * np.sin(u)
z = r * np.sin(v)
return np.array([x, y, z])
def mobius_func(self, u, v):
# Parametric equations for a Möbius strip adjusted to fit inside the torus
radius = 2 # Radius of the central circle
width = 0.6 # Width of the strip
twist = u / 2 # Half-twist
x = (radius + v * np.cos(twist)) * np.cos(u)
y = (radius + v * np.cos(twist)) * np.sin(u)
z = v * np.sin(twist)
return np.array([x, y, z])
def hyperbolic_color_func(self, x, y, z):
# Color function to simulate hyperbolic colors
r = np.sqrt(x**2 + y**2 + z**2)
theta = np.arctan2(y, x)
phi = np.arccos(z / r)
hue = (theta + PI) / (2 * PI)
saturation = 0.8
value = (np.sin(3 * phi) + 1) / 2 # Creates variation based on angle
return color.hsv_to_rgb(np.array([hue, saturation, value]))
from manim import *
import numpy as np
class PenroseTiling(Scene):
def construct(self):
# Generate Penrose tiling
tiling = self.create_penrose_tiling(order=5, scale=2)
self.add(tiling)
self.wait(2)
def create_penrose_tiling(self, order=5, scale=1):
# Initial large kite
tiles = self.deflate_tiles([self.initial_tile()], order)
group = VGroup()
for tile in tiles:
polygon = Polygon(*[scale * np.array(vertex) for vertex in tile['vertices']])
polygon.set_fill(random_bright_color(), opacity=0.7)
polygon.set_stroke(WHITE, width=0.5)
group.add(polygon)
return group
def initial_tile(self):
# Defines the initial 'kite' tile
golden_ratio = (1 + np.sqrt(5)) / 2
angle36 = PI / 5
angle72 = 2 * PI / 5
# Coordinates for the initial kite
A = [0, 0, 0]
B = [np.cos(0), np.sin(0), 0]
C = [np.cos(angle72), np.sin(angle72), 0]
D = [np.cos(-angle36), np.sin(-angle36), 0]
return {
'type': 'kite',
'vertices': [A, B, C, D]
}
def deflate_tiles(self, tiles, order):
if order == 0:
return tiles
new_tiles = []
for tile in tiles:
new_tiles.extend(self.subdivide_tile(tile))
return self.deflate_tiles(new_tiles, order - 1)
def subdivide_tile(self, tile):
# Subdivide tiles according to Penrose rules
golden_ratio = (1 + np.sqrt(5)) / 2
if tile['type'] == 'kite':
A, B, C, D = tile['vertices']
P = self.get_point(A, B, tau=golden_ratio)
new_tiles = [
{'type': 'kite', 'vertices': [P, B, C, D]},
{'type': 'dart', 'vertices': [A, P, D]}
]
elif tile['type'] == 'dart':
A, B, C = tile['vertices']
P = self.get_point(B, A, tau=golden_ratio)
new_tiles = [
{'type': 'kite', 'vertices': [P, B, C, A]}, # Added 'A' as the fourth vertex
{'type': 'dart', 'vertices': [A, P, C]}
]
else:
new_tiles = []
return new_tiles
def get_point(self, point1, point2, tau):
# Calculates a point along the line between two points
return [
point1[0] + (point2[0] - point1[0]) / tau,
point1[1] + (point2[1] - point1[1]) / tau,
0
]
from manim import *
import numpy as np
class KnotToDuck(ThreeDScene):
def construct(self):
# Set up the camera
self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)
# Create the knot
knot = self.create_knot()
# Create the duck
duck = self.create_duck()
# Add the knot to the scene
self.add(knot)
self.wait(1)
# Morph the knot into the duck
self.play(Transform(knot, duck), run_time=5)
self.wait(2)
def create_knot(self):
# Define the parametric equations for the knot
knot = ParametricFunction(
self.knot_equation,
t_range=[0, TAU, TAU / 200], # Step size controls the number of points
color=BLUE_E,
)
knot.set_stroke(width=3)
return knot
def knot_equation(self, t):
# Simple trefoil knot equations
x = (2 + np.cos(3 * t)) * np.cos(2 * t)
y = (2 + np.cos(3 * t)) * np.sin(2 * t)
z = np.sin(3 * t)
return np.array([x, y, z]) / 3 # Scale down for better viewing
def create_duck(self):
# Approximate the duck shape using basic 3D shapes
body = Sphere(radius=1).shift(DOWN * 0.5)
head = Sphere(radius=0.5).shift(UP * 1.0 + OUT * 0.5)
beak = Cone(base_radius=0.2, height=0.3)
beak.rotate(PI / 2, axis=RIGHT).shift(UP * 1.0 + OUT * 0.9)
duck = VGroup(body, head, beak)
duck.set_color(YELLOW)
return duck
from manim import *
import numpy as np
class TorusToBiCylinder(ThreeDScene):
def construct(self):
# Set up the camera
self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)
# Create the Torus
torus = self.create_torus()
torus.set_color(BLUE_E)
torus.set_opacity(0.7)
# Create the Bi-Cylinder (intersection of two cylinders)
bicylinder = self.create_bicylinder()
bicylinder.set_color(RED_E)
bicylinder.set_opacity(0.7)
# Add the Torus to the scene
self.add(torus)
self.wait(1)
# Transform Torus into Bi-Cylinder
self.play(Transform(torus, bicylinder), run_time=5)
self.wait(2)
def create_torus(self):
# Define the torus as a ParametricSurface
torus = ParametricSurface(
self.torus_equation,
u_range=[0, TAU],
v_range=[0, TAU],
resolution=(48, 16),
checkerboard_colors=[BLUE_D, BLUE_E],
)
return torus
def torus_equation(self, u, v):
# Parametric equations for a torus
R = 2 # Major radius
r = 0.7 # Minor radius
x = (R + r * np.cos(v)) * np.cos(u)
y = (R + r * np.cos(v)) * np.sin(u)
z = r * np.sin(v)
return np.array([x, y, z])
def create_bicylinder(self):
# Create two cylinders intersecting at right angles
cylinder1 = Cylinder(radius=2, height=4, direction=UP)
cylinder2 = Cylinder(radius=2, height=4, direction=RIGHT)
bicylinder = Intersection(cylinder1, cylinder2)
return bicylinder
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment