Lucky Spin — House of Legends
Documented: 2026-05-11
Overview
Guests can spin a wheel for a chance to win comp items (free drinks, discounts). One spin per guest per visit.
Spin Flow
Guest visits Photo Wall / Minigames section
│
▼
See "Lucky Spin" prompt
│
▼
Tap "Spin Now" button
│
▼
Spin animation plays (framer-motion)
│
▼
Landing on prize
│
▼
Prize revealed with celebration
│
▼
Comp item added to order OR discount appliedTables
spinPrizes: defineTable({
label: v.string(),
prizeType: v.union(v.literal("MENU_ITEM"), v.literal("DISCOUNT")),
menuItemId: v.optional(v.id("menuItems")),
discountPercent: v.optional(v.number()),
weight: v.number(), // Higher = more likely
enabled: v.boolean(),
createdAt: v.number(),
updatedAt: v.number(),
}).index("by_enabled", ["enabled"]);
spinResults: defineTable({
profileId: v.id("guestProfiles"),
orderId: v.id("orders"),
tableId: v.id("tables"),
prizeId: v.id("spinPrizes"),
displayText: v.string(),
showDate: v.string(),
createdAt: v.number(),
})
.index("by_show_date", ["showDate"])
.index("by_table_show", ["tableId", "showDate"])
.index("by_profile", ["profileId"]);Prize Types
| Type | Description | Example |
|---|---|---|
MENU_ITEM | Free menu item | Free Cocktail |
DISCOUNT | Percentage off bill | 10% off |
Weight System
Higher weight = more likely to land on that prize.
Example config:
| Prize | Type | Weight |
|---|---|---|
| Free Cocktail | MENU_ITEM | 30 |
| 5% Off | DISCOUNT | 25 |
| 10% Off | DISCOUNT | 20 |
| Free Dessert | MENU_ITEM | 15 |
| 15% Off | DISCOUNT | 10 |
Components
| Component | Purpose |
|---|---|
spin-wheel.tsx | Animated wheel (framer-motion) |
spin-trigger.tsx | "Spin Now" button |
spin-result.tsx | Prize reveal modal |
spin-history.tsx | Guest's spin results |
Backend Functions
| Function | Purpose |
|---|---|
minigames.spin | Process spin, select prize |
minigames.getSpinResult | Get guest's spin result |
minigames.getPrizes | Get available prizes |
minigames.applySpinPrize | Apply comp to order |
Animation
Wheel spin uses framer-motion:
animate-spinwith custom easing- Random duration 3-5 seconds
- Lands on prize based on server-side selection (not client random)