Little OBS toy.

Last Updated or created 2025-06-15

I use OBS sometimes to explain things, I thought it would be nice to have a moving avatar thingy in my screencast which moves when I talk.

The image is a transparent PNG, and I’m moving it up and down using the microphone and a python script.

CODE:

import pygame
import pyaudio
import numpy as np
import sys

# Settings
PNG_PATH = "your_image.png"  # Replace with your transparent PNG path
CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
MOVEMENT_THRESHOLD = 1
GRAVITY = 3 # Tweak this, to get smoother "talk" bounch
JUMP_MULTIPLIER = 3  # Controls jump power Tweak this shit
MAX_JUMP_HEIGHT = 30   # Max  bounce 
START_OFFSET = -450      # How far below screen the PNG starts ( so my avator stays covered in bottom )

# Initialize PyAudio
p = pyaudio.PyAudio()
stream = p.open(format=FORMAT,
                channels=CHANNELS,
                rate=RATE,
                input=True,
                frames_per_buffer=CHUNK)

# Initialize Pygame
pygame.init()
info = pygame.display.Info()
screen_width, screen_height = info.current_w, info.current_h
screen = pygame.display.set_mode((screen_width, screen_height), pygame.FULLSCREEN)
pygame.display.set_caption("Mic Bounce PNG")

# Load image
image = pygame.image.load(PNG_PATH).convert_alpha()
img_rect = image.get_rect()
img_rect.centerx = screen_width // 2
img_rect.top = screen_height + START_OFFSET  # Start below the screen

velocity_y = 0
clock = pygame.time.Clock()

def get_loudness():
    data = np.frombuffer(stream.read(CHUNK, exception_on_overflow=False), dtype=np.int16)
    volume = np.linalg.norm(data)
    return volume / CHUNK

# Bottom and top bounce limits
bottom_y = screen_height + START_OFFSET
top_y = screen_height + START_OFFSET - MAX_JUMP_HEIGHT

try:
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT or \
               (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
                raise KeyboardInterrupt

        loudness = get_loudness()

        if loudness > MOVEMENT_THRESHOLD and img_rect.top >= bottom_y:
            # Jump upward with capped power
            velocity_y = -int(min((loudness - MOVEMENT_THRESHOLD) * JUMP_MULTIPLIER, MAX_JUMP_HEIGHT))

        # Apply gravity
        velocity_y += GRAVITY
        img_rect.y += velocity_y

        if img_rect.top >= bottom_y:
            img_rect.top = bottom_y
            velocity_y = 0

        if img_rect.top <= top_y:
            img_rect.top = top_y
            velocity_y = 0

        # Draw chromakey green background
        screen.fill((0, 255, 0))

        # Draw PNG
        screen.blit(image, img_rect)

        pygame.display.flip()
        clock.tick(60)

except KeyboardInterrupt:
    stream.stop_stream()
    stream.close()
    p.terminate()
    pygame.quit()
    sys.exit()

Spread the love

Leave a Reply

Your email address will not be published. Required fields are marked *