OhMyGame
OhMyGame is the open-source studio for making games with AI. Design, build, playtest, and publish games in one app, with your own model keys.
Build your Viking tribe, train an army and raid rival clans in this Telegram strategy game.
GamesTypeScript · CSSGitHub @parsakhosravaniOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗A Telegram Mini App strategy game: grow your tribe, build 24 buildings, train an army, raid other players and barbarian camps, and climb the leaderboard. A short Daily Mine (tapping with combos, weak spots and Frenzy) gives a daily boost, and a 7-day login streak rewards coming back.
This repo is the whole game — the Next.js frontend and its backend (API routes + a SQLite/Turso database). The server is authoritative: every tap, upgrade and reward is checked and saved on the server, so progress survives reloads and devices and can't be faked from the browser.
| Piece | Where |
|---|---|
| Game rules and balance numbers (costs, rates, rewards) | src/lib/game/config.ts |
| Game engine — pure functions shared by server and client | src/lib/game/engine.ts |
| Telegram sign-in verification (initData HMAC) | src/server/auth.ts |
Database (Turso or local SQLite, tables auto-created; bump SCHEMA_VERSION when you change the schema) and players | src/server/db.ts, src/server/players.ts |
| API routes | src/app/api/* |
| Client state, tap batching, live counters | src/context/resource/ResourceContext.tsx |
initData on every request (Authorization: tma <initData>). The server checks the signature with your bot token, so nobody can play as someone else.TELEGRAM_CHANNEL_ID is set and the bot is an admin there. YouTube and X can't be verified by any bot, so they unlock after the player opens the link and waits a few seconds.{ taps, crits, comboSum, frenzyTaps }; the server caps tap speed, weak-spot share (40%), combo (×2) and only allows Frenzy once the meter really filled.All numbers are in src/lib/game/config.ts; the rules are in src/lib/game/war.ts (tests in war.test.ts).
Admins broadcast news from the bot chat. To become an admin, either put your Telegram user id in BOT_ADMIN_IDS (comma-separated for several admins), or open https://t.me/valorians_bot?start=admin_<code>, where the code is BOT_ADMIN_CODE if set, otherwise the first 32 hex characters of sha256("<bot token>:admin") (keep it private): the bot makes you an admin and right away sends a test announcement of the live version (with 🧪 Send to me only to preview it safely). Then in @valorians_bot:
/announce.TELEGRAM_CHANNEL_ID is set and the bot can post there) and Cancel.Sending runs at ~25 messages a second: a first batch right away, the rest from the cron (/api/cron/battles, every 5 minutes), picking up where it stopped. When it's done the bot messages you how many players got it. Each announcement carries a Play now button and a Mute news button; players can also toggle news with /news. Players who blocked the bot are skipped until they write to it again. Battle alerts are not affected by muting.
After each deploy the bot notices the new version (Vercel's VERCEL_GIT_COMMIT_SHA) right after the deploy finishes and announces it to every player automatically, listing the pull requests merged since the last version (their titles are the bullet points, so write them for players). Admins get a note when it goes out and when it's delivered; the news channel gets it too when TELEGRAM_CHANNEL_ID is set. A deploy whose changes can't be read is skipped. Admins choose how from the bot with /releases: 🚀 Automatic, ✋ Ask me first (a draft for each version: Send / Send to me only / Write my own / Cancel) or 🔕 Off (only /announce). The choice is kept in the database; until an admin picks one, RELEASE_ANNOUNCE (auto, draft or off) decides.
Admin commands (in admins' own / menu, refreshed after each deploy and whenever an admin sends a command): /announce, /cancel, /stats (players, new and active players, reachable, Plus, Stars, clans) and /releases.
A monthly subscription paid in Telegram Stars, the only way Telegram allows Mini Apps to sell digital goods. It sells convenience, never power:
Every player can take a 3-day free trial once. The price is PLUS_PRICE_STARS (default 150 Stars); perks and trial length live in PLUS in config.ts.
How a payment flows: the app asks /api/plus/invoice for a subscription invoice link (createInvoiceLink with a 30-day subscription_period) and opens it with Telegram.WebApp.openInvoice. Telegram sends the bot a pre_checkout_query, which src/server/plus.ts checks and approves, then a successful_payment message on the first payment and on every monthly renewal. Each payment is stored in the payments table by its charge id, so a repeated update never counts twice, and Plus runs until the renewal date Telegram reports. Players cancel from Telegram (Settings → My Stars); Plus then runs out at the end of the paid month. A refund (refundStarPayment) ends Plus right away. The bot also has a /plus command.
The webhook must receive pre_checkout_query updates. The cron re-runs the bot setup by itself when the webhook is missing them, so existing deploys pick this up within minutes; you can also open /api/bot/setup once.
All routes need the Authorization header and return { serverTime, me, state } unless noted.
| Method | Route | Body |
|---|---|---|
| GET | /api/me | — signs in, creating the player on first visit |
| POST | /api/tap | { resource, taps, crits?, comboSum?, frenzyTaps? } |
| POST | /api/skills/upgrade | { skill: "tap" | "energy" } |
| POST | /api/streak | — claims today's streak reward |
| POST | /api/buildings/upgrade | { building: "iron-mine" } (ids in config.ts) |
| POST | /api/quests/start | { quest: "telegram" | "youtube" | "x" } |
| POST | /api/quests/claim | { quest } |
| GET | /api/clan?q= | — returns { mine, clans[], limits }: your clan with members, and clans to browse |
| POST | /api/clan/create | { name, tag, description? } — costs coins |
| POST | /api/clan/join | { id } |
| POST | /api/clan/leave | — |
| POST | /api/clan/kick | { id } — leader only |
| POST | /api/war/train | { unit, count } (unit ids in config.ts) |
| GET | /api/war/targets | — tribes you can raid now |
| POST | /api/war/raid | { target: playerId, units } — also returns report |
| POST | /api/war/camp | { level, units } — also returns report |
| GET | /api/war/reports | — your last 30 battles |
| GET | /api/leaderboard?by=population|power|wins |
Errors come back as { error, code } with status 400 (game rule) or 401 (sign-in).
bun install
Create .env.local to play in a normal browser with a test player:
NEXT_PUBLIC_DEV_LOGIN=true
NEXT_PUBLIC_BOT_ADDRESS=YourBot
NEXT_PUBLIC_TELEGRAM_CHANNEL=yourchannel
NEXT_PUBLIC_YOUTUBE_CHANNEL=yourchannel
NEXT_PUBLIC_TWITTER_CHANNEL=yourhandle
bun dev # http://localhost:3000
bun run test # engine + auth tests
Add ?dev_user=2 to the URL to play as a different test player (handy for testing clans with several members).
/newapp to create the Mini App. Its short name goes in NEXT_PUBLIC_APP_SHORT_NAME.libsql://…) and create a token for it.TELEGRAM_BOT_TOKEN, TURSO_DATABASE_URL, TURSO_AUTH_TOKENNEXT_PUBLIC_BOT_ADDRESS, NEXT_PUBLIC_APP_SHORT_NAME, and the quest links (NEXT_PUBLIC_TELEGRAM_CHANNEL, …)NEXT_PUBLIC_DEV_LOGIN in production.
Redeploy after adding them (NEXT_PUBLIC_* values are baked in at build time).Node.js 24 is required (pinned in package.json).
Without Turso the game still runs on Vercel, but it can only store players in /tmp, which Vercel wipes whenever it restarts the server — so progress can reset. Add the two Turso variables to make it permanent; no code change needed.
Leave the Turso variables empty and the game uses a local SQLite file at DATABASE_PATH, which needs a persistent disk. With Docker:
docker build -t valorians \
--build-arg NEXT_PUBLIC_BOT_ADDRESS=YourBot \
--build-arg NEXT_PUBLIC_APP_SHORT_NAME=start \
--build-arg NEXT_PUBLIC_TELEGRAM_CHANNEL=yourchannel .
docker run -p 3000:3000 -v valorians-data:/data -e TELEGRAM_BOT_TOKEN=... valorians
Back up /data/valorians.db regularly.
All balance numbers live in src/lib/game/config.ts: starting resources, production per hour, tap power and energy curves, building costs and times, quest rewards, clan limits and founding cost. The server and client both read it, so a change there applies everywhere.
| — top 50 and your rank |
| POST | /api/plus/trial | — starts the one free Plus trial |
| POST | /api/plus/invoice | — returns { link }, a Stars subscription invoice for Plus |