Latest blog post
How I Built a Tarot Game in Roblox Over a Weekend
May 18, 2025

How I Built a Tarot Game in Roblox Over a Weekend

Avatar’s Fate: A Tarot Simulator – A Developer’s Breakdown

👩‍💻 The Goal

I wanted to create a UI-based tarot simulator in Roblox with:

  • A shuffle and draw mechanic
  • Upright/reversed card logic
  • Reveal animation with meaning overlays
  • No avatars, movement, or 3D interaction—just clean interface work

I gave myself a weekend to prototype and publish.

🧠 Design Philosophy: MVP + Magic

Because I had limited time, I leaned into the following principles:

  • Focus on one mechanic: Draw a tarot card. That’s the core loop.
  • 2D UI only: All game logic happens in the GUI layer—no 3D elements or character controllers.
  • Keep art static: I used a fixed set of 22 tarot images I designed elsewhere.

🛠️ Tools Used

  • Roblox Studio – Core development
  • ChatGPT/ Photoshop – Card meaning descriptions / Card illustrations
  • Elevenlabs.io - Text to speech AI voiceovers
  • Studio Scripts – Lua, all local and module-based
  • No external frameworks (yet) – MVP kept it tight

🔄 Core Systems

1. Deck & Draw Logic

Cards are stored in a ModuleScript as a table of dictionaries:

local Deck = {    
	{ name = "The Fool", id = "card_00", meaning = "...", reversed = "..." },    
	{ name = "The Magician", id = "card_01", meaning = "...", reversed = "..." },    
-- etc}

A DrawCard() function:

  • Clones a card GUI template
  • Randomly selects a card from the deck
  • Applies a 50/50 upright/reversed orientation
  • Animates into position

Cards are removed or reshuffled depending on game mode.

2. Card Reveal Animation

Reveal is handled with a TweenPosition and TweenRotation chain:

local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
local flipTween = TweenService:Create(cardFrame, tweenInfo, { Rotation = 90 })

flipTween:Play()
flipTween.Completed:Connect(function()    	  
	cardImage.Image = revealImage    
	cardFrame.Rotation = -90    
	TweenService:Create(cardFrame, tweenInfo, { Rotation = 0 }):Play()
end)

Simple, smooth, and mobile-safe.

3. Upright vs Reversed Meaning Overlay

When the card is drawn, a text overlay fades in with either the upright or reversed meaning.

‍‍if isReversed then    
	meaningLabel.Text = cardData.reversed    
	cardImage.Rotation = 180
else    
	meaningLabel.Text = cardData.meaning
end

The overlay fades in based on user input timing.

4. Audio Feedback

Each card has a unique voiceover. When revealed:

local sound = Instance.new("Sound", cardFrame)
sound.SoundId = "rbxassetid://12345678" -- stored in module
sound:Play()

I fed the card meaning scripts into ElevenLabs.io, using the Old Wizard voice for narration. The result gives each card a mysterious, immersive vibe that enhances the draw experience.

🧪 Playtesting Notes

Playtesting... didn’t really happen 😅

I tested myself, iterated quickly, and made sure nothing broke. Because the experience is single-player and visual, I focused on user flow and animation timing. I had to rework the layout again once I remembered to check on mobile 😅- its not perfect but readable.

⚙️ What Worked

  • Keeping it 2D-only made UI testing faster and removed camera issues
  • Skipping avatars let me ship faster and focus on storytelling

💡 What’s Next

  • A daily card draw system (reward hook + longer engagement)
  • A meta-system for readings (e.g., 3-card spreads)

👩‍🚀 Final Thoughts

If you're a solo dev or a parent trying to ship something meaningful without losing sleep, here’s my advice:

  • Design around your time budget
  • Cut scope aggressively
  • Prioritize flow and delight over complexity
  • Know what you can layer in later

Avatar’s Fate is a small game. But it’s complete. And I built it between kid stuff, chores, and a lot of “maybe later”s.

And that feels kind of magical.

Check out Avatar's Fate: A Tarot Simulator!

Post link
Posts you might like