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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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()
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()
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 *