BeamNG.Earth
BeamNG.drive용 1:1 비율 실시간 지구, 실제 고도·위성 이미지·부동 원점·보조 서버에서 LOD 스트리밍
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 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.