clawdbot-workspace/oskv_logo_anim.py

209 lines
6.3 KiB
Python

from manim import *
import numpy as np
import random
class OSKVLogoReveal(Scene):
def construct(self):
self.camera.background_color = "#050510"
# === PART 1: Particles converge to center ===
particles = VGroup()
for _ in range(100):
dot = Dot(
point=np.array([
random.uniform(-8, 8),
random.uniform(-5, 5),
0
]),
radius=random.uniform(0.02, 0.06),
color=random.choice([WHITE, BLUE_B, PURPLE_B])
)
dot.set_opacity(random.uniform(0.3, 0.8))
particles.add(dot)
self.add(particles)
# Converge to center
self.play(
*[dot.animate.move_to(
np.array([random.uniform(-0.5, 0.5), random.uniform(-0.2, 0.2), 0])
).set_opacity(0) for dot in particles],
run_time=1.5,
rate_func=rush_into
)
self.remove(particles)
# === PART 2: Flash and logo image appears ===
# White flash
flash = Rectangle(
width=16, height=10,
fill_color=WHITE,
fill_opacity=0.8,
stroke_width=0
)
self.play(FadeIn(flash, run_time=0.1))
self.play(FadeOut(flash, run_time=0.3))
# Load the actual OSKV logo
logo = ImageMobject("/Users/jakeshore/.clawdbot/workspace/oskv_logo.png")
logo.scale_to_fit_width(8)
logo.set_opacity(0)
self.add(logo)
# Fade in the logo
self.play(logo.animate.set_opacity(1), run_time=1)
# === PART 3: Geometric frame builds around logo ===
# Inner frame
inner_frame = RoundedRectangle(
width=9, height=3,
corner_radius=0.3,
color=WHITE,
stroke_width=1.5
)
inner_frame.set_stroke(opacity=0.5)
# Outer frame
outer_frame = RoundedRectangle(
width=10, height=3.8,
corner_radius=0.4,
color=BLUE_B,
stroke_width=1
)
outer_frame.set_stroke(opacity=0.3)
self.play(
Create(inner_frame),
run_time=0.8
)
self.play(
Create(outer_frame),
run_time=0.6
)
# === PART 4: Orbiting dots ===
orbit_dots = VGroup()
orbit_trails = VGroup()
n_orbits = 6
for i in range(n_orbits):
dot = Dot(radius=0.06, color=[BLUE, PURPLE, TEAL, WHITE, BLUE_B, PURPLE_B][i])
dot.set_glow_factor(1.5)
angle = i * TAU / n_orbits
radius_x = 5.5
radius_y = 2.2
dot.move_to([
radius_x * np.cos(angle),
radius_y * np.sin(angle),
0
])
orbit_dots.add(dot)
self.play(
LaggedStart(*[GrowFromCenter(d) for d in orbit_dots], lag_ratio=0.1),
run_time=0.6
)
# Orbit around the logo
orbit_anims = []
for i, dot in enumerate(orbit_dots):
orbit_anims.append(
Rotate(dot, TAU * 0.4, about_point=ORIGIN)
)
self.play(*orbit_anims, run_time=2, rate_func=smooth)
# === PART 5: Pulse effect ===
# Scale pulse
logo_group = VGroup(inner_frame, outer_frame)
self.play(
logo.animate.scale(1.08),
logo_group.animate.scale(1.08),
*[dot.animate.scale(1.5).set_opacity(0.5) for dot in orbit_dots],
rate_func=there_and_back,
run_time=0.6
)
# === PART 6: Expanding ring waves ===
for _ in range(2):
ring = Circle(radius=0.5, color=BLUE_B, stroke_width=3)
ring.set_stroke(opacity=0.8)
self.add(ring)
self.play(
ring.animate.scale(12).set_stroke(opacity=0),
run_time=0.8,
rate_func=rush_from
)
self.remove(ring)
# === PART 7: Corner accents ===
corners = VGroup()
corner_positions = [
(UP + LEFT, 0), (UP + RIGHT, -PI/2),
(DOWN + RIGHT, PI), (DOWN + LEFT, PI/2)
]
for pos, rot in corner_positions:
corner = VGroup(
Line(ORIGIN, RIGHT * 0.5, color=TEAL, stroke_width=2),
Line(ORIGIN, UP * 0.5, color=TEAL, stroke_width=2)
)
corner.rotate(rot)
corner.move_to(pos * np.array([4.8, 1.8, 0]))
corners.add(corner)
self.play(
LaggedStart(*[Create(c) for c in corners], lag_ratio=0.1),
run_time=0.6
)
# === PART 8: Ambient floating particles ===
ambient = VGroup()
for _ in range(40):
p = Dot(
radius=random.uniform(0.01, 0.04),
color=random.choice([WHITE, BLUE_B, PURPLE_B, TEAL])
)
p.set_opacity(random.uniform(0.15, 0.4))
p.move_to([random.uniform(-7, 7), random.uniform(-4, 4), 0])
ambient.add(p)
self.play(FadeIn(ambient), run_time=0.3)
# Gentle upward drift
drift_anims = [
p.animate.shift(UP * random.uniform(0.3, 0.8)).set_opacity(0)
for p in ambient
]
# Second pulse while particles drift
self.play(
*drift_anims,
logo.animate.scale(1.05),
logo_group.animate.scale(1.05),
rate_func=there_and_back,
run_time=2
)
# === PART 9: Final hold with slow orbit ===
final_orbit = [
Rotate(dot, TAU * 0.15, about_point=ORIGIN)
for dot in orbit_dots
]
self.play(*final_orbit, run_time=2, rate_func=linear)
# Hold
self.wait(1)
# === PART 10: Fade to black ===
everything = VGroup(logo_group, orbit_dots, corners)
self.play(
FadeOut(everything),
logo.animate.set_opacity(0),
FadeOut(ambient),
run_time=1.5
)