尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 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 |