felt/docs/felt_pricing_model_v2.py

323 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
Felt Pricing Model v2
Key insights from Mikkel:
- Offline (Leaf hardware) is a separate value from Pro features
- Display nodes: cost-recovery only, no recurring
- Casinos need tiered pricing (independent, small chain, large)
- €25/mo for offline capability alone
- €75/mo additional for full Pro features (cash, dealers, loyalty etc)
"""
EUR_TO_DKK = 7.45
print("=" * 70)
print("FELT PRICING MODEL v2")
print("=" * 70)
print("""
┌─────────────────────────────────────────────────────────────────┐
│ PRICING PHILOSOPHY │
│ │
│ FREE → Hook them. Full tournament engine in cloud. │
│ OFFLINE ADD-ON → They need reliability. Leaf hardware. │
│ PRO → They need operations. Cash, dealers, loyalty. │
│ CASINO TIERS → They need scale. Enterprise features. │
└─────────────────────────────────────────────────────────────────┘
""")
# ================================================================
# TIER DEFINITIONS
# ================================================================
print("=" * 70)
print("VENUE TIERS")
print("=" * 70)
tiers = [
{
"name": "Free",
"price": 0,
"target": "Enthusiast clubs, small bars, anyone starting",
"includes": [
"Full tournament engine (unlimited)",
"Player mobile access",
"Signage editor with AI assist",
"Leagues & seasons",
"Player database & history",
"Regional tournament participation",
],
"requires": "Internet connection (virtual Leaf in our cloud)",
},
{
"name": "Offline",
"price": 25,
"target": "Any venue that needs reliability / wants displays",
"includes": [
"Everything in Free",
"Dedicated Leaf node (hardware purchase required)",
"Full offline operation — runs without internet",
"Wireless display nodes (purchase separately)",
"Custom domain support",
"Remote admin access via Netbird",
],
"requires": "Leaf hardware (~€120) + display nodes (~€30 each)",
},
{
"name": "Pro",
"price": 100, # 25 offline + 75 pro features
"target": "Serious venues wanting the full platform",
"includes": [
"Everything in Offline",
"Cash game management (waitlists, sessions, rake)",
"Dealer scheduling & shift management",
"Player loyalty system",
"Membership management",
"Advanced analytics & reporting",
"TDD data import wizard",
"Priority support",
],
"requires": "Leaf hardware (included free with annual plan)",
},
]
for t in tiers:
print(f"\n {'' * 60}")
if t['price'] == 0:
print(f" {t['name'].upper():30s} €0/mo")
elif t['name'] == 'Pro':
print(f" {t['name'].upper():30s}{t['price']}/mo (€25 offline + €75 pro)")
else:
print(f" {t['name'].upper():30s}{t['price']}/mo")
print(f" Target: {t['target']}")
print(f" Requires: {t['requires']}")
print(f" Includes:")
for item in t['includes']:
print(f"{item}")
# ================================================================
# CASINO / ENTERPRISE TIERS
# ================================================================
print(f"\n\n{'=' * 70}")
print("CASINO & ENTERPRISE TIERS")
print("=" * 70)
casino_tiers = [
{
"name": "Casino Starter",
"price": "€249/mo",
"target": "Independent casino with 1 poker room (5-15 tables)",
"tables": "Up to 15 tables",
"includes": [
"Everything in Pro",
"Multi-room support (tournament room + cash room)",
"Floor manager role with restricted permissions",
"Shift reporting & payroll export",
"Compliance-ready audit trail",
"8hr response SLA",
],
},
{
"name": "Casino Pro",
"price": "€499/mo per property",
"target": "Small casino chain (2-5 properties, 15-40 tables each)",
"tables": "Up to 40 tables per property",
"includes": [
"Everything in Casino Starter",
"Multi-property dashboard",
"Cross-property player tracking",
"Cross-property loyalty (play at A, redeem at B)",
"Centralized dealer pool management",
"API access for POS/CMS integration",
"Custom branding & white-label displays",
"4hr response SLA",
"Dedicated onboarding",
],
},
{
"name": "Casino Enterprise",
"price": "Custom (€999+/mo)",
"target": "Large operators (5+ properties, 40+ tables each)",
"tables": "Unlimited",
"includes": [
"Everything in Casino Pro",
"Unlimited properties",
"Fleet management (remote Leaf provisioning & updates)",
"Regional analytics & benchmarking",
"Casino management system API integration (Bally's, IGT, L&W)",
"Custom feature development",
"White-label everything (player app, venue pages)",
"2hr response SLA + dedicated account manager",
"On-site installation support",
],
},
]
for t in casino_tiers:
print(f"\n {'' * 60}")
print(f" {t['name'].upper():30s} {t['price']}")
print(f" Target: {t['target']}")
print(f" Tables: {t['tables']}")
print(f" Includes:")
for item in t['includes']:
print(f"{item}")
# ================================================================
# HARDWARE PRICING
# ================================================================
print(f"\n\n{'=' * 70}")
print("HARDWARE PRICING (cost-recovery, no margin on displays)")
print("=" * 70)
hardware = [
("Leaf Node", 120, 120, "Venue brain, NVMe, locked down"),
("Display Node", 25, 30, "Pi Zero W2 + case + power, per unit"),
("Display Node (4-pack)", 90, 110, "4× display nodes, slight discount"),
]
print(f"\n {'Device':<25s} {'Our Cost':>10s} {'Sell Price':>12s} Notes")
print(f" {'' * 65}")
for name, cost, price, notes in hardware:
margin = price - cost
print(f" {name:<25s}{cost:>7}{price:>9} {notes}")
print(f"""
Leaf hardware options:
• Buy outright: €120
• Free with 12-month Offline or Pro annual plan
• Casino tiers: hardware included in contract
Display nodes:
• Priced at cost + shipping
• No recurring fee — they're dumb render devices
• Venues buy as many as they need (most want 2-6)
""")
# ================================================================
# REVENUE MODEL WITH NEW PRICING
# ================================================================
print(f"\n{'=' * 70}")
print("REVISED FINANCIAL MODEL")
print("=" * 70)
# Infrastructure cost (from capacity analysis)
INFRA_PER_FREE = 0.45 # Actual cost per virtual Leaf (from capacity model)
INFRA_PER_PAID = 0.15 # Pro/Offline on Core (just sync)
INFRA_BASE = 100 # One Hetzner server
TARGET_ANNUAL_DKK = 60000 * 2 * 12 # 2× 60k DKK/mo
TARGET_ANNUAL_EUR = TARGET_ANNUAL_DKK / EUR_TO_DKK
print(f"\n Target: 2× {60000:,} DKK/mo = {TARGET_ANNUAL_DKK:,} DKK/yr = ~€{TARGET_ANNUAL_EUR:,.0f}/yr")
print(f" Infrastructure: €{INFRA_BASE}/mo base (real cost from capacity analysis)")
scenarios = [
# (name, free, offline, pro, casino_starter, casino_pro, casino_enterprise, casino_ent_price)
("Year 1: Denmark", 80, 8, 5, 0, 0, 0, 0),
("Year 2: Nordics + first casino", 250, 20, 15, 2, 0, 0, 0),
("Year 3: N. Europe + UK", 500, 40, 35, 5, 1, 0, 0),
("Year 4: International", 800, 60, 60, 8, 3, 1, 1499),
]
print(f"\n {'' * 66}")
for name, free, offline, pro, cs, cp, ce, ce_price in scenarios:
# Revenue
rev_offline = offline * 25
rev_pro = pro * 100
rev_cs = cs * 249
rev_cp = cp * 499
rev_ce = ce * (ce_price if ce_price else 999)
total_rev = rev_offline + rev_pro + rev_cs + rev_cp + rev_ce
# Costs
cost_free = free * INFRA_PER_FREE
cost_paid = (offline + pro + cs + cp + ce) * INFRA_PER_PAID
total_cost = INFRA_BASE + cost_free + cost_paid
# Add second server if >400 free venues
if free > 400:
total_cost += 100
net = total_rev - total_cost
annual_net = net * 12
dkk = annual_net * EUR_TO_DKK
per_person = dkk / 2 / 12
pct = per_person / 60000 * 100
total_venues = free + offline + pro + cs + cp + ce
total_paying = offline + pro + cs + cp + ce
print(f"\n {name}")
print(f" Total venues: {total_venues} ({free} free, {total_paying} paying)")
detail = f" Paying: {offline} offline, {pro} pro"
if cs: detail += f", {cs} casino-start"
if cp: detail += f", {cp} casino-pro"
if ce: detail += f", {ce} casino-ent"
print(detail)
print(f" Revenue: €{total_rev:>7,.0f}/mo Costs: €{total_cost:>6,.0f}/mo Net: €{net:>7,.0f}/mo")
print(f" Annual: €{annual_net:>8,.0f}{dkk:>10,.0f} DKK/yr → {per_person:>7,.0f} DKK/mo per person", end="")
if pct >= 95:
print(f"")
else:
print(f" ({pct:.0f}%)")
# ================================================================
# THE CASINO MULTIPLIER EFFECT
# ================================================================
print(f"\n\n{'=' * 70}")
print("THE CASINO MULTIPLIER")
print("=" * 70)
print(f"""
One Casino Pro deal (5 properties × €499/mo) = €2,495/mo = €29,940/yr
That single deal is worth:
• 100 Offline venues (€25/mo each)
• 25 Pro venues (€100/mo each)
• 10 Casino Starter venues (€249/mo each)
Two Casino Pro deals + modest venue growth:
2× Casino Pro: €4,990/mo
30 Pro venues: €3,000/mo
20 Offline venues: €500/mo
────────────────────────────
Total: €8,490/mo → €101,880/yr → ~759,000 DKK/yr
Per person: ~31,600 DKK/mo (53% of target)
Add ONE Casino Enterprise deal and you're close to target
with under 100 total paying venues.
The path:
1. Saturate Denmark free tier (prove the product)
2. Convert enthusiast venues to Offline/Pro (prove revenue)
3. Use those as case studies to land first casino deal
4. Casino revenue subsidizes everything else
""")
# ================================================================
# PRICING COMPARISON
# ================================================================
print(f"{'=' * 70}")
print("WHAT VENUES PAY TODAY (for comparison)")
print(f"{'=' * 70}")
print(f"""
TDD License: $130 one-time (but stuck on Windows PC)
BravoPokerLive: $200-500/mo (US, waitlist-focused)
Casino CMS poker module: $2,000-10,000/mo (Bally's, IGT, L&W)
Digital signage software: €30-80/mo (separate subscription)
Generic waitlist apps: €20-50/mo
Spreadsheets: Free (but hours of manual work)
Felt Offline at €25/mo replaces TDD + adds wireless displays +
mobile + signage. That's a no-brainer for any venue currently
on TDD who spends any money on their operation.
Felt Pro at €100/mo replaces TDD + digital signage + waitlist
app + spreadsheets + manual comp tracking. Five tools for the
price of one.
Casino Starter at €249/mo is 1/10th what they pay for their
current casino management poker module — and it's better.
""")