Spaces:
Sleeping
Sleeping
A newer version of the Gradio SDK is available: 6.26.0
metadata
title: Flip Card Component
emoji: π΄
colorFrom: blue
colorTo: indigo
sdk: gradio
sdk_version: 6.18.0
python_version: '3.13'
app_file: app.py
pinned: true
license: apache-2.0
short_description: Card matching game with emoji pairs and 3D card flips
π΄ Flip Card
A custom Gradio HTML component for a memory matching card game.
Flip cards, find matching emoji pairs, use presets, add custom emojis, and track completed games.
Inspired by MatchWise. The original prototype was expanded into a reusable application and now includes a custom HTML component for improved interactivity and integration.
Features
- Built with
gr.HTML - Smooth 3D card flip animation
- Match and wrong-pair feedback
- Preset and custom emoji input
- Responsive grid up to 4Γ4
- Result output through
props.value - Game history display
Files Structure
.
βββ app.py # Demo Gradio app
βββ flip_card.py # Reusable FlipCard component
βββ requirements.txt
βββ README.md
Install and Run
pip install -r requirements.txt
python app.py
Then open http://127.0.0.1:7860 in your browser.
Quick Start
import gradio as gr
from flip_card import FlipCard
with gr.Blocks() as demo:
game = FlipCard()
result = gr.Textbox(label="Result")
game.change(
fn=lambda value: value or "",
inputs=game,
outputs=result,
)
demo.launch()
Usage with Presets, Custom Emojis, and History
import gradio as gr
from flip_card import DEFAULT_EMOJIS, PRESETS, FlipCard, update_flip_card
def on_win(result: str | None, history: list[str] | None):
if not result:
return "", "", history or []
history = (history or []) + [result]
history_text = "\n".join(
f"{i}. {item}"
for i, item in enumerate(reversed(history[-10:]), start=1)
)
return result, history_text, history
def change_preset(name: str):
emojis = PRESETS.get(name, DEFAULT_EMOJIS).copy()
return (
update_flip_card(emojis=emojis),
emojis,
",".join(emojis),
"",
)
def parse_emojis(text: str | None):
emojis = [item.strip() for item in (text or "").split(",") if item.strip()]
emojis = list(dict.fromkeys(emojis))
return emojis[:8] if len(emojis) >= 2 else DEFAULT_EMOJIS.copy()
def apply_custom(text: str | None):
emojis = parse_emojis(text)
return update_flip_card(emojis=emojis), emojis, ""
def new_game(emojis: list[str] | None):
return update_flip_card(emojis=emojis or DEFAULT_EMOJIS.copy()), ""
with gr.Blocks() as demo:
game = FlipCard()
result = gr.Textbox(label="Result", interactive=False)
history_box = gr.Textbox(label="Game History", lines=6, interactive=False)
preset = gr.Dropdown(
label="Preset",
choices=list(PRESETS.keys()),
value="Fruits",
)
custom = gr.Textbox(
label="Custom Emojis",
value="π,π",
placeholder="Example: πΆ,π±,π¦,πΌ",
)
apply_btn = gr.Button("Apply Custom Emojis")
new_btn = gr.Button("New Shuffled Game")
current_emojis = gr.State(DEFAULT_EMOJIS.copy())
history = gr.State([])
game.change(
fn=on_win,
inputs=[game, history],
outputs=[result, history_box, history],
)
preset.change(
fn=change_preset,
inputs=preset,
outputs=[game, current_emojis, custom, result],
)
apply_btn.click(
fn=apply_custom,
inputs=custom,
outputs=[game, current_emojis, result],
)
new_btn.click(
fn=new_game,
inputs=current_emojis,
outputs=[game, result],
)
demo.launch()
Component API
FlipCard(
value=None,
emojis=None,
cards=None,
cards_json=None,
grid_cols=None,
game_id=None,
**kwargs
)
Parameters
value: Final winning message.emojis: List of emojis used to create matching pairs.cards: Pre-built shuffled card list.cards_json: Internal JSON card state.grid_cols: Number of grid columns.game_id: Unique id used to reset frontend state.
Presets
from flip_card import PRESETS
Available presets:
FruitsAnimalsSpaceFoodNatureChallenge
Updating the Component
Use update_flip_card() when changing cards from an event handler.
from flip_card import update_flip_card
def change_game():
return update_flip_card(emojis=["πΆ", "π±", "π¦", "πΌ"])
Do not return a new FlipCard() instance from event handlers.
License
MIT