Table of Contents
Radial Breathing Loop
Radial pulsing pattern with smooth breathing animation that loops over 600 frames.
Loop Guarantee
Breathing (300 frames), radial (60 frames), angular (40 frames), and color (50 frames) periods all divide 600.
Mathematical Formula
R = \sqrt{x^2 + y^2}
\theta = \arctan2(y, x)
\text{breath} = 0.5 + 0.5 \cdot \sin(\frac{2\pi t}{300})
\text{radial} = \sin(R \cdot k_r - \frac{2\pi t}{60})
\text{angular} = \sin(\theta \cdot k_a + \frac{2\pi t}{40})
\text{pattern} = \text{radial} \times \text{angular} \times \text{breath}
Where:
- Breathing period: 300 frames
- Radial period: 60 frames
- Angular period: 40 frames
- Color period: 50 frames
How It Works
This pattern creates a radial "breathing" effect:
- Convert to polar coordinates (radius, angle)
- Create a breathing pulse that expands and contracts
- Add radial waves emanating from center
- Add angular waves rotating around center
- Combine all effects
- Map to color with time-based cycling
Implementation
import torch
width, height = 512, 512
fps = 60
duration = 10
total_frames = fps * duration
frames = []
for t in range(total_frames):
x = torch.linspace(-1, 1, width)
y = torch.linspace(-1, 1, height)
X, Y = torch.meshgrid(x, y, indexing='ij')
R = torch.sqrt(X**2 + Y**2)
theta = torch.atan2(Y, X)
# Breathing: complete 2 cycles over 600 frames (300-frame period)
breath = 0.5 + 0.5 * torch.sin(t * (2*torch.pi/300))
# Radial wave with 60-frame period
radial = torch.sin(R * 10 - t * (2*torch.pi/60))
# Angular wave with 40-frame period
angular = torch.sin(theta * 5 + t * (2*torch.pi/40))
pattern = radial * angular * breath
# Psychedelic color mapping
r = torch.sin(pattern * 3 + t * (2*torch.pi/50))
g = torch.sin(pattern * 3 + t * (2*torch.pi/50) + 2*torch.pi/3)
b = torch.sin(pattern * 3 + t * (2*torch.pi/50) + 4*torch.pi/3)
rgb = torch.stack([r, g, b], dim=-1)
rgb = ((rgb + 1) / 2).clamp(0, 1)
frames.append(rgb)
output_image = torch.stack(frames, dim=0)
Line-by-Line Explanation
R = torch.sqrt(X**2 + Y**2)
Radial distance from center. Center is 0, corners are ~1.41.
theta = torch.atan2(Y, X)
Angular position in radians. Ranges from -π to π.
breath = 0.5 + 0.5 * torch.sin(t * (2*torch.pi/300))
Breathing pulse. Period of 300 frames (half the total duration). Completes 2 full breath cycles over 600 frames.
radial = torch.sin(R * 10 - t * (2*torch.pi/60))
Radial wave emanating from center. Period of 60 frames. The - sign makes waves move outward.
angular = torch.sin(theta * 5 + t * (2*torch.pi/40))
Angular wave rotating around center. Period of 40 frames.
pattern = radial * angular * breath
Multiplies all three effects. The breathing modulates the overall intensity.
r = torch.sin(pattern * 3 + t * (2*torch.pi/50))
Color mapping with period of 50 frames.
Mathematical Insight
Why These Periods?
- 300: 600 / 300 = 2 (2 breath cycles)
- 60: 600 / 60 = 10 (10 radial wave cycles)
- 40: 600 / 40 = 15 (15 angular rotations)
- 50: 600 / 50 = 12 (12 color cycles)
All divide 600 evenly, ensuring perfect looping.
Breathing Effect
breath = 0.5 + 0.5 * sin(2πt/300)
This creates a value that:
- Oscillates between 0 and 1
- Has period of 300 frames
- Completes 2 full cycles over 600 frames
Multiplying the pattern by breath makes the entire effect pulse in and out.
Polar Coordinates
Using polar coordinates (R, θ) makes radial and angular effects much easier to implement than Cartesian coordinates.
Customization
Faster Breathing
breath = 0.5 + 0.5 * torch.sin(t * (2*torch.pi/150)) # 150-frame period
More Radial Waves
radial = torch.sin(R * 15 - t * (2*torch.pi/60))
Different Angular Pattern
angular = torch.sin(theta * 8 + t * (2*torch.pi/40))
No Breathing
breath = 1.0 # Constant
Performance Notes
torch.sqrt()andtorch.atan2()are fast- All operations are vectorized
- No expensive filtering
Loop Verification
# After generating frames
first_frame = output_image[0]
last_frame = output_image[-1]
diff = torch.abs(first_frame - last_frame).max()
print(f"Max difference: {diff.item()}")
# Should be close to 0