Streamlit Animator

:briefcase: Title

Looking for expert streamlit animators to help me with a game I’ve created.

We’ll set up a payment schedule for the project after we figure out if we are a good fit. Thanks!

Hey Michael

I have extensive experience working with streamlit, I would love to help you with your game.
github

Thanks!

Hey @Michael43 ,

Interested, if deemed fit please feel free to reach out via GitHub @ aryadhruv

I need a ton of animation help - here’s an example of one of the games within my game: It’s a slot machine that I want to work better and be more fun! → do you think you can help ? # Streamlit Lottie Slot Machine :slot_machine:

--------------------------------

Quick start:

pip install streamlit streamlit-lottie requests

streamlit run slot_app.py

Swap the Lottie URLs below with your own, OR put .json files in ./lottie/

and load them with load_lottie(“lottie/lever.json”) etc.

import time

import random

from pathlib import Path

import json

import requests

import streamlit as st

from streamlit_lottie import st_lottie

st.set_page_config(page_title=“:slot_machine: Slot Machine”, page_icon=“:slot_machine:”, layout=“centered”)

----------------------------

LOTTIE LOADING HELPERS

----------------------------

def load_lottie(src: str):

“”“Load Lottie from a URL or a local .json path.”“”

try:

if src.startswith(“http”):

r = requests.get(src, timeout=10)

if r.status_code == 200:

return r.json()

else:

st.warning(f"Lottie URL failed: {src} (HTTP {r.status_code})")

return None

else:

p = Path(src)

if p.exists():

return json.loads(p.read_text(encoding=“utf-8”))

else:

st.warning(f"Lottie file not found: {src}")

return None

except Exception as e:

st.warning(f"Could not load Lottie: {e}")

return None

----------------------------

PLACEHOLDER LOTTIE ASSETS

(Replace these with your own!)

----------------------------

A gentle looping “idle” light effect (placeholder)

IDLE_URL = “https://assets9.lottiefiles.com/packages/lf20_q5pk6p1k.json

A lever pull animation (placeholder)

LEVER_URL = “https://assets7.lottiefiles.com/private_files/lf30_editor_e7qk3x0q.json

A spin/whirl overlay (placeholder)

SPIN_URL = “https://assets4.lottiefiles.com/packages/lf20_touohxv0.json

Confetti for wins (optional but oh-so necessary)

CONFETTI_URL = “https://assets1.lottiefiles.com/packages/lf20_jbrw3hcz.json

L_IDLE = load_lottie(IDLE_URL)

L_LEVER = load_lottie(LEVER_URL)

L_SPIN = load_lottie(SPIN_URL)

L_CONFETTI = load_lottie(CONFETTI_URL)

----------------------------

SLOT MODEL

----------------------------

REELS = 3

SYMBOLS = [“:cherries:”, “:lemon:”, “:grapes:”, “:bell:”, “:star:”, “:seven:”, “:gem_stone:”]

WEIGHTS = [5, 5, 4, 3, 2, 1, 1] # Rarity: cherries/lemons common, 7s & diamonds rare

PAYOUTS = {

three-of-a-kind payouts (feel free to rebalance)

:cherries:”: 5,

:lemon:”: 8,

:grapes:”: 12,

:bell:”: 20,

:star:”: 30,

:seven:”: 50,

:gem_stone:”: 100,

}

SPIN_SPEED = 0.08 # seconds between frame updates while spinning

STOP_DELAY_PER_REEL = 0.6 # stagger stop between reels

def weighted_choice():

pool =

for s, w in zip(SYMBOLS, WEIGHTS):

pool.extend([s]*w)

return random.choice(pool)

def spin_reels():

generate a final combo using weights

return [weighted_choice() for _ in range(REELS)]

def calc_payout(result):

Only pay for three-of-a-kind in this simple model

if len(set(result)) == 1:

return PAYOUTS.get(result[0], 0)

return 0

----------------------------

SESSION STATE

----------------------------

if “credits” not in st.session_state:

st.session_state.credits = 100

if “last_result” not in st.session_state:

st.session_state.last_result = [" ", " ", " "]

if “message” not in st.session_state:

st.session_state.message = “Welcome! Pull the lever to play.”

----------------------------

UI

----------------------------

st.title(“:slot_machine: Streamlit Lottie Slots”)

st.caption(“Pull the lever, watch the reels spin, and pray to the RNG gods.”)

with st.container(border=True):

Idle animation at the top (lights, flair)

if L_IDLE:

st_lottie(L_IDLE, height=100, key=“idle”, loop=True)

else:

st.write(“:sparkles: (Idle lights would be here—swap in a Lottie asset!)”)

Credits + Controls

colA, colB, colC = st.columns([1,1,1])

with colA:

st.metric(“Credits”, value=st.session_state.credits)

with colB:

bet = st.number_input(“Bet”, min_value=1, max_value=10, value=5, step=1)

with colC:

add = st.button(“:money_bag: Add 100 credits”, use_container_width=True)

if add:

st.session_state.credits += 100

Reels Display

reel_area = st.empty()

msg_area = st.empty()

anim_area = st.empty()

def render_reels(reels: list[str]):

Big chunky display for the reels

rcols = st.columns(REELS, vertical_alignment=“center”)

for i, sym in enumerate(reels):

with rcols[I]:

st.markdown(

f"“”

{sym}

“”",

unsafe_allow_html=True

)

def do_spin():

if st.session_state.credits < bet:

st.session_state.message = “Not enough credits. Add more or lower your bet.”

return

Deduct bet

st.session_state.credits -= bet

st.session_state.message = “Spinning…”

msg_area.info(st.session_state.message)

Lever animation (quick)

if L_LEVER:

anim_area.empty()

with anim_area:

st_lottie(L_LEVER, height=140, key=f"lever-{time.time()}", loop=False)

time.sleep(0.6)

else:

msg_area.write(“:backhand_index_pointing_right: (Lever pull Lottie goes here)”)

Spin overlay while reels animate

spin_container = st.container()

if L_SPIN:

with spin_container:

st_lottie(L_SPIN, height=120, key=f"spin-{time.time()}", loop=True)

Animate spinning reels with staggered stops

start_time = time.time()

running = [True]*REELS

current = [random.choice(SYMBOLS) for _ in range(REELS)]

target = spin_reels()

while any(running):

for i in range(REELS):

if running[I]:

current[i] = random.choice(SYMBOLS)

with reel_area:

render_reels(current)

time.sleep(SPIN_SPEED)

Staggered stopping

elapsed = time.time() - start_time

for i in range(REELS):

if running[i] and elapsed > (i+1)*STOP_DELAY_PER_REEL:

running[i] = False

current[i] = target[I]

with reel_area:

render_reels(current)

time.sleep(0.12)

Final result

spin_container.empty()

st.session_state.last_result = target

payout = calc_payout(target)

if payout > 0:

st.session_state.credits += payout * bet

st.session_state.message = f":collision: WIN! {target[0]} {target[1]} {target[2]} → Payout: {payout*bet}"

if L_CONFETTI:

st_lottie(L_CONFETTI, height=200, key=f"confetti-{time.time()}", loop=False)

else:

st.session_state.message = f"Miss! {target[0]} {target[1]} {target[2]} → Try again."

msg_area.success(st.session_state.message)

Reels (initial render)

with reel_area:

render_reels(st.session_state.last_result)

Pull lever button (full width for drama)

pull = st.button(“:bullseye: Pull Lever”, use_container_width=True, type=“primary”)

if pull:

do_spin()

If you can replace the Lottie URLs new assets for a custom fun experience. Add paylines, sounds, and a jackpot to get fancy.