examples

76 interactive examples

hover example to preview

1

Snake 3D

audio
2

Creating Yoyo Animation

3

Creating Wooden Planks Animation

4

Creating Windstorm Animation

5

Creating Windmill Animation

6

Creating Whale Animation

7

Creating Waterfall Animation

8

Creating Volcano Animation

9

Creating Vaporwave Animation

10

Creating Tree Animation

11

Creating Tornado Animation

12

Creating Sun Animation

13

Creating Stone Wall Animation

14

Creating Spring Animation

15

Creating Spider Animation

16

Creating Spaceship Animation

17

Creating Solar System Educational Animation

18

Creating Solar System Animation

19

Creating Snowglobe Animation

20

Creating Snake Animation

21

Creating Sailboat Animation

22

Creating Robot Animation

23

Creating River Rapids Animation

24

Creating Rainbow Animation

25

Creating Prism Animation

26

Creating Pinwheel Animation

27

Creating Pine Tree Animation

28

Creating Phoenix Animation

29

Creating Pendulum Animation

30

Creating Octopus Animation

31

Creating Mushroom Animation

32

Creating Metronome Animation

33

Creating Meteor Animation

34

Creating Metal Plates Animation

35

Creating Lissajous Animation

36

Creating Lightning Animation

37

Creating Lighthouse Animation

38

Creating Lava Lamp Animation

39

Creating Lantern Animation

40

Creating Kite Animation

41

Creating Kaleidoscope Animation

42

Creating Jellyfish Animation

43

Creating Inner Planets Orbit Animation

44

Creating Hourglass Animation

45

Creating Hive Animation

46

Creating Grass Animation

47

Creating Geyser Animation

48

Creating Gear Animation

49

Creating Fountain Animation

50

Creating Flower Animation

51

Creating Fish Animation

52

Creating Fireworks Animation

53

Creating Fern Animation

54

Creating Earth Orbit Animation

55

Creating Dragon Animation

56

Creating Disco Ball Animation

57

Creating Demon Animation

58

Creating Crystallization Animation

59

Creating Crystal Animation

60

Creating Cosmic Formation Animation

61

Creating Coral Reef Animation

62

Creating Compass Animation

63

Creating Cloud Animation

64

Creating Clock Animation

65

Creating Castle Animation

66

Creating Carousel Animation

67

Creating Candle Animation

68

Creating Campfire Animation

69

Creating Cactus Animation

70

Creating Butterfly Animation

71

Creating Bush Animation

72

Creating Brick Wall Animation

73

Creating Blackhole Animation

74

Creating Beehive Animation

75

Creating Aurora Animation

76

🎈 Floating Balloons

hover for preview

Creating Yoyo Animation

published on 8/21/2025
interactive example

3D Voxel YoYo Animation Tutorial

This guide walks you through how to generate a looping 3D voxel animation of a yo-yo using SpatialStudio. The script creates a colorful yo-yo that bounces up and down with a realistic string inside a cubic 3D space, then saves the animation to a .splv file.


What this script does

  • Creates a 3D scene of size 128×128×128
  • Spawns 1 yo-yo with:
    • Two circular disc halves forming the yo-yo body
    • A realistic string that extends and retracts
    • Metallic highlights for a glossy finish
    • Smooth up-and-down bouncing motion
  • Animates the yo-yo for 6 seconds at 30 FPS with realistic physics
  • Outputs the file yoyo.splv that you can play in your viewer

How it works (simplified)

  1. Voxel volume Each frame is a 3D grid filled with RGBA values (SIZE × SIZE × SIZE × 4).

  2. Yo-yo body The yo-yo consists of two disc-shaped halves with a narrow connecting axle in the middle.

  3. String physics The string length changes dynamically based on the yo-yo's position, simulating realistic string extension and retraction.

  4. Bounce motion Uses sine wave functions to create smooth up-and-down motion with acceleration and deceleration.

  5. Highlights Metallic highlights are added to the yo-yo discs to simulate light reflection and give it a realistic appearance.

  6. Animation loop A normalized time variable t cycles from 0 → 2π, ensuring the motion loops smoothly with the yo-yo returning to its starting position.

  7. Encoding Frames are passed into splv.Encoder, which writes them into the .splv video file.


Try it yourself

Install requirements first:

pip install spatialstudio numpy tqdm

Then copy this script into yoyo.py and run:

python yoyo.py

Full Script

import numpy as np
from spatialstudio import splv
from tqdm import tqdm

# Scene setup
SIZE, FPS, SECONDS = 128, 30, 6
FRAMES = FPS * SECONDS
CENTER_X = CENTER_Y = CENTER_Z = SIZE // 2
OUT_PATH = "../outputs/yoyo.splv"

# Yo-yo settings
YOYO_RADIUS = 12
YOYO_THICKNESS = 4
AXLE_RADIUS = 3
MAX_STRING_LENGTH = 40
BOUNCE_AMPLITUDE = 30

def add_voxel(volume, x, y, z, color):
    if 0 <= x < SIZE and 0 <= y < SIZE and 0 <= z < SIZE:
        volume[x, y, z, :3] = color
        volume[x, y, z, 3] = 255

def generate_yoyo_disc(volume, cx, cy, cz, radius, thickness, color, t):
    """Generate one half of the yo-yo (disc shape)"""
    for dx in range(-radius, radius+1):
        for dy in range(-thickness//2, thickness//2+1):
            for dz in range(-radius, radius+1):
                distance = np.sqrt(dx*dx + dz*dz)
                if distance <= radius:
                    # Add subtle texture variation
                    texture = int(np.sin(dx*0.2 + dz*0.2 + t*0.3) * 3)
                    brightness = 1.0 + texture * 0.05
                    final_color = tuple(min(255, int(c * brightness)) for c in color)
                    add_voxel(volume, cx+dx, cy+dy, cz+dz, final_color)

def generate_yoyo_axle(volume, cx, cy, cz, radius, height, color):
    """Generate the central axle of the yo-yo"""
    for dx in range(-radius, radius+1):
        for dy in range(-height//2, height//2+1):
            for dz in range(-radius, radius+1):
                if dx*dx + dz*dz <= radius*radius:
                    add_voxel(volume, cx+dx, cy+dy, cz+dz, color)

def generate_string(volume, start_x, start_y, start_z, end_y, t):
    """Generate the yo-yo string with slight swaying motion"""
    string_color = (139, 69, 19)  # Brown string
    string_length = abs(end_y - start_y)
    
    for i in range(int(string_length)):
        progress = i / string_length if string_length > 0 else 0
        # Add slight swaying motion
        sway = np.sin(t * 3.0 + progress * 8) * 2
        x = start_x + int(sway * progress * 0.3)
        y = start_y + i
        z = start_z + int(np.sin(t * 2.0 + progress * 5) * 0.5)
        add_voxel(volume, x, y, z, string_color)

def generate_yoyo_highlights(volume, cx, cy, cz, t):
    """Add metallic highlights to the yo-yo"""
    highlight_color = (255, 255, 255)
    
    # Top disc highlights
    for dx in range(-3, 4):
        for dz in range(-3, 4):
            if dx*dx + dz*dz <= 9:
                add_voxel(volume, cx-6+dx, cy-YOYO_THICKNESS+1, cz-4+dz, highlight_color)
    
    # Bottom disc highlights  
    for dx in range(-3, 4):
        for dz in range(-3, 4):
            if dx*dx + dz*dz <= 9:
                add_voxel(volume, cx-6+dx, cy+YOYO_THICKNESS-1, cz-4+dz, highlight_color)

def generate_yoyo_body(volume, cx, cy, cz, t):
    """Generate the complete yo-yo body"""
    # Yo-yo colors (red and blue discs)
    top_color = (220, 20, 60)    # Crimson red
    bottom_color = (30, 144, 255)  # Dodger blue
    axle_color = (169, 169, 169)   # Dark gray
    
    # Generate top disc
    generate_yoyo_disc(volume, cx, cy - YOYO_THICKNESS//2, cz, 
                      YOYO_RADIUS, YOYO_THICKNESS, top_color, t)
    
    # Generate bottom disc
    generate_yoyo_disc(volume, cx, cy + YOYO_THICKNESS//2, cz, 
                      YOYO_RADIUS, YOYO_THICKNESS, bottom_color, t)
    
    # Generate axle
    generate_yoyo_axle(volume, cx, cy, cz, AXLE_RADIUS, YOYO_THICKNESS * 2, axle_color)
    
    # Add highlights
    generate_yoyo_highlights(volume, cx, cy, cz, t)

def calculate_yoyo_position(t):
    """Calculate yo-yo position based on realistic bouncing motion"""
    # Use a combination of sine waves to create realistic yo-yo motion
    # The yo-yo accelerates down and decelerates up
    bounce_cycle = np.sin(t) * 0.5 + 0.5  # Normalize to 0-1
    
    # Apply easing for more realistic motion
    if bounce_cycle < 0.5:
        # Going down - accelerating
        eased = 2 * bounce_cycle * bounce_cycle
    else:
        # Going up - decelerating  
        eased = 1 - 2 * (1 - bounce_cycle) * (1 - bounce_cycle)
    
    y_offset = int(BOUNCE_AMPLITUDE * eased)
    return y_offset

def generate_scene(volume, t):
    """Generate the complete scene for one frame"""
    # Calculate yo-yo position
    y_offset = calculate_yoyo_position(t)
    yoyo_y = CENTER_Y - BOUNCE_AMPLITUDE//2 + y_offset
    
    # Generate yo-yo body
    generate_yoyo_body(volume, CENTER_X, yoyo_y, CENTER_Z, t)
    
    # Generate string from hand (top) to yo-yo
    hand_y = CENTER_Y - BOUNCE_AMPLITUDE//2 - 20  # Hand position above yo-yo
    generate_string(volume, CENTER_X, hand_y, CENTER_Z, yoyo_y - YOYO_THICKNESS, t)
    
    # Add a simple "hand" at the top
    hand_color = (255, 220, 177)  # Skin color
    for dx in range(-2, 3):
        for dy in range(-3, 1):
            for dz in range(-2, 3):
                if dx*dx + dz*dz <= 4:
                    add_voxel(volume, CENTER_X+dx, hand_y+dy, CENTER_Z+dz, hand_color)

# Initialize encoder
enc = splv.Encoder(SIZE, SIZE, SIZE, framerate=FPS, outputPath=OUT_PATH, motionVectors="off")

# Generate animation frames
for frame in tqdm(range(FRAMES), desc="Generating yo-yo animation"):
    volume = np.zeros((SIZE, SIZE, SIZE, 4), dtype=np.uint8)
    t = (frame / FRAMES) * 2*np.pi  # Normalized time for smooth looping
    generate_scene(volume, t)
    enc.encode(splv.Frame(volume, lrAxis="x", udAxis="y", fbAxis="z"))

enc.finish()
print(f"Created {OUT_PATH}")

Next steps

  • Adjust BOUNCE_AMPLITUDE to change how far the yo-yo travels
  • Modify YOYO_RADIUS and YOYO_THICKNESS to create different yo-yo sizes
  • Change the disc colors by editing top_color and bottom_color
  • Add spin rotation by modifying the highlight positions over time
  • Create multiple yo-yos by calling generate_yoyo_body() with different positions
  • Experiment with different easing functions in calculate_yoyo_position() for varied motion styles