BeamNG.Earth
A 1:1 scale streamed Earth for BeamNG.drive: real elevation and satellite imagery, floating origin, LOD streaming from a companion server
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗A free, public arcade of games built with AI. Every game listed here was made with AI tools and is free to play in the browser.
It's a static site: Vite + vanilla TypeScript, no third-party fonts or CDNs. The one third-party script is Google Analytics 4 (gtag.js, which sets cookies); it and cookieless Vercel Web Analytics count page views and a few custom events (see src/analytics.ts). First-party games come from one file, public/games.json. Signed-in players can also submit their own games, which appear after review (see Accounts and submissions). What the site stores is described on the privacy page.
/): a grid of game cards. Each card links straight to the game's live URL (new tab)./play.html?id=<game-id>): gives the game the whole screen in an iframe, with a small control pill (back, full screen, open in new tab, Ko-fi tip, feedback) for when embedding doesn't work well. See Play page sizing.npm install
npm run dev # local dev server
npm run build # type-check + production build to dist/
npm run preview # serve dist/ locally
Add one entry to public/games.json:
{
"id": "my-game",
"name": "My Game",
"description": "One sentence about the game",
"playUrl": "https://my-game.vercel.app",
"thumbnail": "/thumbs/my-game.png",
"status": "live",
"repo": "https://github.com/you/my-game"
}
| Field | Notes |
|---|---|
id | Unique, URL-safe slug (a-z, 0-9, -). Used in play.html?id=… and /games/<id>/. |
name | Display name. |
description | Short one-liner shown on the card. |
playUrl | Live game URL. Must be https://; entries with other schemes are ignored. |
thumbnail | Path under public/, starting with /. Must be local (the CSP only allows same-origin images). |
status | e.g. live (green badge) or beta (yellow badge); anything else gets a neutral badge. |
repo | Optional source link (https://). |
minWidth, minHeight | Optional. Smallest portrait viewport (CSS px) the game fits. Default 360×600. See Play page sizing. |
minWidthLandscape, minHeightLandscape | Optional. Same for landscape. Default 640×360. |
Add a thumbnail at public/thumbs/<id>.png, 1280×720 (16:9). To capture a real screenshot of the live game with Playwright:
npx playwright install chromium # first time only
node scripts/thumb.mjs https://my-game.vercel.app public/thumbs/my-game.png
The script loads the page at 1280×720, waits ~8 seconds for the game to render, then saves the PNG. With no arguments it re-captures Super Star Party.
Then save a WebP copy next to it, public/thumbs/<id>.webp (quality about 80, e.g. cwebp -q 80 in.png -o out.webp). It's optional but worth it: the WebP is about a sixth of the PNG's size. When it exists, the cards and game page serve it through a and keep the PNG as the fallback and for social cards.
Everything is generated at build (and dev) time from public/games.json by scripts/seo.mjs, wired up in vite.config.ts. Adding a game to games.json updates all of it automatically.
/games/<id>/): one static HTML page per game (title, description, canonical, Open Graph/Twitter tags using the thumbnail, VideoGame JSON-LD, Play links). Vite config writes them to games/<id>/index.html (gitignored, rebuilt every run) and adds them as build inputs, so they land in dist/games/<id>/index.html. Styles: src/style.css + src/game-page.css; script: src/game-page.ts. Ids must be URL-safe slugs (^[a-z0-9-]+$) or the build fails./): the game cards and the "N games ready to play" count are prerendered into index.html so crawlers see real links without JS (src/home.ts still re-renders the grid). WebSite + Organization + ItemList JSON-LD is injected into the head./sitemap.xml: the home page plus every /games/<id>/ page (play.html is noindex, follow and not listed). public/robots.txt points to it./llms.txt and /llms-full.txt: plain-text guides for AI assistants and agents (llmstxt.org): what the site is, every game's page and play link, and the full description of each game. public/robots.txt names the main AI crawlers (ChatGPT, Claude, Perplexity, Google's AI and others) in the same group as *, so they read every public page.vercel.json): trueaigaming.vercel.app 308-redirects to https://trueaigaming.com; any other *.vercel.app host (branch previews) gets X-Robots-Tag: noindex, nofollow.index.html has a commented, empty slot for the google-site-verification meta tag. Not needed if the domain is verified with a DNS TXT record.public/og.png (1200×630 social card) comes from node scripts/og.mjs. Favicons (favicon.ico 16/32/48, favicon-32.png, apple-touch-icon.png, icon-192.png, icon-512.png) are rendered from public/favicon.svg by node scripts/icons.mjs. Both use Playwright ( first); commit the resulting PNGs. lists the icons.The play page sizes the game frame to the area you can actually see. It tracks visualViewport, so the frame follows Safari's toolbars showing and hiding, rotation and full screen. The frame is inset by the device's safe areas (notch, home indicator), because iOS reports zero insets inside an iframe. Without JS, the CSS falls back to 100vh / -webkit-fill-available / 100dvh.
games.json overrides it with minWidth/minHeight or minWidthLandscape/minHeightLandscape (numbers from 200 to 4000; anything else is ignored). If the usable area is smaller in either direction, the iframe is rendered larger and scaled down with transform: scale(s), where s = min(usableW / minW, usableH / minH). The logical size keeps the screen's aspect ratio, so the scaled game still fills the screen, and it never gets less than its minimum. Browsers map taps and clicks into a scaled iframe natively."minWidth": 320, "minHeight": 560) to stay 1:1.play.ts sets --vw, --vh, --usable-w, --usable-h and --vmin on <html>, plus the classes is-portrait/is-landscape and size-compact (usable short side < 500px), size-regular (< 900px) or size-wide. #stage[data-scale] holds the current scale.To check it, run node tools/probe-play.mjs against a preview build (npm run build && npx vite preview --host 127.0.0.1 --port 4173 --strictPort). It loads the play page in WebKit and Chromium at ten phone, tablet and desktop sizes, and checks frame fit, overflow, tap targets, HUD placement, the feedback dialog and input mapping. It writes shots/responsive/report.json, screenshots and a contact sheet, and exits 1 on any failure. Use --url=, --sizes=375x635,844x390 or --browsers=webkit to point it elsewhere or narrow it down. Playwright can't simulate safe-area insets or Safari's real toolbars, so test on a real phone too.
The site is hosted on Vercel and auto-deploys from git:
main → Vercel runs npm run build and deploys dist/ to production.vercel.json sets the framework (Vite) and applies security headers to every route:
*.public.blob.vercel-storage.com, for submitted thumbnails), network requests from the site itself plus the Supabase project, iframes only from allowed game origins (submitted games are never framed), and the site itself can't be framedX-Content-Type-OptionsReferrer-PolicyX-Frame-Options: DENYPermissions-PolicyPlayers can sign in (Supabase) and submit games. Approved submissions are added to the site at build time, so the site stays static. Set these in the Vercel project (or a local .env); never commit values.
| Variable | Used by | Notes |
|---|---|---|
SUPABASE_URL | server, build | Supabase project URL. |
SUPABASE_ANON_KEY | server | Supabase anon key, used by the API to check a signed-in user. |
SUPABASE_SERVICE_ROLE_KEY | server, build | Secret. Full database access, so it must never reach the browser. |
DEPLOY_HOOK_URL | server | Secret. Vercel deploy hook the API calls to rebuild the site after an approval. |
VITE_SUPABASE_URL | browser | Same project URL, for the sign-in client. |
VITE_SUPABASE_ANON_KEY | browser | Public anon key, for the sign-in client. |
BLOB_PUBLIC_HOST | server, build | The Blob store's public host, such as abc123.public.blob.vercel-storage.com. Set it before launch (see below). |
VITE_TURNSTILE_SITE_KEY | browser | Public Cloudflare Turnstile site key. When set, sign-up, sign-in, reset and resend carry a bot-check token. Set it together with Supabase's CAPTCHA protection (see the launch steps). |
SUBMISSIONS_ENABLED | server, build | true turns the server side on (see below). |
VITE_SUBMISSIONS_ENABLED | browser | true turns the pages on (see below). |
Only the VITE_ variables reach the browser (Vite inlines them at build time). Everything else stays on the server and in the build.
SUBMISSIONS_ENABLED is the launch switch. When it is not true, the account, submit, profile and admin pages show "Submissions are not open yet", the submission APIs answer 503, and the build lists no submitted games. Turn on SUBMISSIONS_ENABLED and VITE_SUBMISSIONS_ENABLED together, then redeploy. The build needs SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY when it is on, and fails if they are missing.
BLOB_PUBLIC_HOST must be set before launch. When it is set, a submitted thumbnail must be on exactly that host, the build fails on an approved row whose thumbnail is on another host, and approving such a row is refused. When it is not set, any *.public.blob.vercel-storage.com store is accepted, so a thumbnail could point at someone else's store. Use the host only, with no https:// and no trailing slash. Find it in the Vercel Blob store's settings (the part of a file's public URL before the first /).
Age. Accounts are for people 13 and up. The sign-up form asks for a birth month and year, checks them with checkSignupAge in src/shared/submission-rules.mjs, and stores only age_confirmed: true in the signup metadata. A "no" closes the sign-up form for the rest of the browser session. The server makes no profile (so no submissions) for an account without that flag. Playing needs no account, so players are never asked.
The full launch checklist (Supabase, email sender, Turnstile, DNS, Vercel settings) is in docs/accounts-launch.md.
Submitted thumbnails go to their own public Vercel Blob store, through THUMBNAIL_BLOB_READ_WRITE_TOKEN (connect the store to the project with the env var prefix THUMBNAIL_BLOB). The feedback API uses the separate private store behind BLOB_READ_WRITE_TOKEN; a public upload to that store would fail. BLOB_PUBLIC_HOST is the thumbnail store's host.
<picture>If the game is NOT hosted on *.vercel.app, add its origin to frame-src in the Content-Security-Policy header in vercel.json. Otherwise the play page's iframe will be blocked:
frame-src https://super-star-party.vercel.app https://*.vercel.app https://my-game.example.com;
The game's own site must also allow being framed (no X-Frame-Options: DENY or restrictive frame-ancestors). If it doesn't, the card's main Play button still works, because it opens the game in a new tab.
Run npm run build, then commit and push. The game's card, its /games/<id>/ page, the home JSON-LD, sitemap.xml and llms.txt are all generated from games.json (see SEO).
Optional SEO fields: longDescription (game page text and meta description), about (a longer "About" paragraph on the game page; howItWasMade also shows there), seoTitle (overrides the derived <title>), minPlayers / maxPlayers (players badge and JSON-LD numberOfPlayers), author (JSON-LD, defaults to Devin Norris).
npx playwright install chromiumpublic/site.webmanifestpublic/404.html: served by Vercel for unknown paths.