clawdbot-workspace/epic_ad_report_card_v2.py

198 lines
6.6 KiB
Python

from manim import *
import numpy as np
class EpicAdReportCardV2(ThreeDScene):
def construct(self):
self.camera.background_color = "#0a0a1a"
self.set_camera_orientation(phi=0 * DEGREES, theta=-90 * DEGREES, zoom=0.8)
# ============ ACT 1: EPIC INTRO WITH 3D SHAPES ============
# Create a grid of cubes that form the backdrop
cubes = VGroup()
for x in range(-4, 5):
for y in range(-3, 4):
cube = Cube(side_length=0.3, fill_color=BLUE_E, fill_opacity=0.15, stroke_width=0.5, stroke_color=BLUE_D)
cube.shift(x * 0.6 * RIGHT + y * 0.6 * UP)
cubes.add(cube)
# Scatter cubes in z-space initially
for i, cube in enumerate(cubes):
cube.shift(OUT * np.random.uniform(-8, -3))
cube.set_opacity(0)
# Fly cubes into grid formation
self.play(
*[cube.animate.shift(IN * np.random.uniform(3, 8)).set_opacity(0.15) for cube in cubes],
run_time=2,
rate_func=rush_from
)
# ============ ACT 2: TITLE SLAM ============
# Title - positioned flat facing camera
title_line1 = Text("ADVERTISING", font_size=84, color=WHITE, weight=BOLD)
title_line2 = Text("REPORT CARD", font_size=84, color=GOLD, weight=BOLD)
title_line2.next_to(title_line1, DOWN, buff=0.2)
title_group = VGroup(title_line1, title_line2)
title_group.shift(UP * 0.5)
# Scale up from nothing with flash
title_group.scale(0.01)
flash = Circle(radius=0.1, color=GOLD, fill_opacity=1, stroke_width=0)
self.play(
title_group.animate.scale(100),
flash.animate.scale(80).set_opacity(0),
run_time=1,
rate_func=rush_from
)
self.remove(flash)
# Pulse effect
self.play(
title_group.animate.scale(1.15),
rate_func=there_and_back,
run_time=0.4
)
self.play(
title_group.animate.scale(1.08),
rate_func=there_and_back,
run_time=0.3
)
self.wait(0.5)
# ============ ACT 3: CAMERA TILT TO REVEAL 3D DEPTH ============
# Now tilt the camera to show depth
self.move_camera(phi=55 * DEGREES, theta=-70 * DEGREES, run_time=2, added_anims=[
title_group.animate.shift(UP * 1.5),
cubes.animate.set_opacity(0.08)
])
# ============ ACT 4: 3D RATING BARS ============
labels_data = [
("IMPACT", RED_C, 0.95),
("CLARITY", BLUE_C, 0.88),
("ROI", GREEN_C, 0.92),
("CREATIVITY", YELLOW_C, 0.97),
("STRATEGY", PURPLE_C, 0.90),
]
all_bars = VGroup()
for i, (label, color, rating) in enumerate(labels_data):
# 3D bar using a rectangular prism
bar_width = 5 * rating
bar = Prism(dimensions=[bar_width, 0.35, 0.25], fill_color=color, fill_opacity=0.85, stroke_width=1, stroke_color=WHITE)
bar.shift(LEFT * (5 - bar_width) / 2) # align left
# Background bar
bg_bar = Prism(dimensions=[5, 0.35, 0.25], fill_color=GRAY, fill_opacity=0.2, stroke_width=0.5, stroke_color=GRAY)
# Label
label_text = Text(label, font_size=22, color=WHITE, weight=BOLD)
label_text.next_to(bg_bar, LEFT, buff=0.4)
# Percentage
pct = Text(f"{int(rating*100)}%", font_size=28, color=color, weight=BOLD)
pct.next_to(bg_bar, RIGHT, buff=0.4)
row = VGroup(label_text, bg_bar, bar, pct)
row.shift(DOWN * i * 0.65)
all_bars.add(row)
all_bars.shift(DOWN * 0.8)
# Animate each bar sliding in from the left
for i, row in enumerate(all_bars):
label_text, bg_bar, bar, pct = row
# Start positions
bar.save_state()
bar_target = bar.copy()
bar.stretch(0.01, 0) # squish to nothing
bar.align_to(bg_bar, LEFT)
self.play(
FadeIn(label_text, shift=RIGHT * 0.5),
FadeIn(bg_bar),
run_time=0.2
)
self.play(
bar.animate.restore(),
FadeIn(pct, shift=LEFT * 0.3),
run_time=0.4,
rate_func=rush_from
)
self.wait(0.5)
# ============ ACT 5: EPIC CAMERA ORBIT ============
self.begin_ambient_camera_rotation(rate=0.15)
self.wait(4)
self.stop_ambient_camera_rotation()
# ============ ACT 6: GRAND FINALE ============
# Return camera to front
self.move_camera(phi=0 * DEGREES, theta=-90 * DEGREES, run_time=1.5)
# Clear bars with style
self.play(
*[row.animate.shift(RIGHT * 15) for row in all_bars],
title_group.animate.shift(UP * 8),
cubes.animate.set_opacity(0),
run_time=1,
rate_func=rush_into
)
self.remove(all_bars, title_group, cubes)
# Final epic text
final1 = Text("EXCELLENCE", font_size=120, color=GOLD, weight=BOLD)
final2 = Text("DELIVERED", font_size=120, color=WHITE, weight=BOLD)
final2.next_to(final1, DOWN, buff=0.15)
finale = VGroup(final1, final2)
# Star burst effect
lines = VGroup()
for angle in range(0, 360, 15):
line = Line(ORIGIN, RIGHT * 8, color=GOLD, stroke_width=2, stroke_opacity=0.6)
line.rotate(angle * DEGREES)
lines.add(line)
lines.scale(0.01)
finale.scale(0.01)
self.play(
finale.animate.scale(100),
lines.animate.scale(100).set_opacity(0),
run_time=1.2,
rate_func=rush_from
)
self.remove(lines)
# Final pulse
self.play(
finale.animate.scale(1.1),
rate_func=there_and_back,
run_time=0.5
)
# Add a subtle glow ring
ring = Annulus(inner_radius=2.5, outer_radius=3, color=GOLD, fill_opacity=0.3, stroke_width=0)
ring.shift(DOWN * 0.3)
self.play(
FadeIn(ring),
ring.animate.scale(1.5).set_opacity(0),
run_time=1.5
)
self.remove(ring)
self.wait(1.5)