Underground 2 Revived
Play Need for Speed: Underground 2 (2004) in Chrome and Firefox with WebGPU graphics, Web Audio, up to 120 fps widescreen, controller support, free roam and Online races with friends. Fan project, not
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
Безкоштовна браузерна гра в хрестики-нулики на Next.js 15 (App Router) + Firebase, з повноцінним SEO-шаром: метадані, sitemap/robots, JSON-LD, блог, i18n-заготовка, менеджер реклами, аналітика, PWA. Відкрийте http://localhost:3000. Next.js читає .env.local лише при старті сервера - після будь-якої зміни файлу перезапустіть npm run dev. Ігрові роути (/, /play, /play/[roomId], /admin) навмисно лишились поза (marketing) route group і виглядають так само, як і раніше - нова навігація/реклама на них не впливає.查看完整 README ↗
Безкоштовна браузерна гра в хрестики-нулики на Next.js 15 (App Router) + Firebase, з повноцінним SEO-шаром: метадані, sitemap/robots, JSON-LD, блог, i18n-заготовка, менеджер реклами, аналітика, PWA.
cd tictactoe-game
npm install
cp .env.local.example .env.local # заповніть Firebase-ключі та (опційно) SEO/ads/analytics
npm run dev
Відкрийте http://localhost:3000.
Next.js читає
.env.localлише при старті сервера - після будь-якої зміни файлу перезапустітьnpm run dev.
app/
page.tsx - головна: сама гра (vs AI), поза (marketing) групою
play/, play/[roomId]/ - онлайн-кімнати (Firebase), не займані SEO-шаром
admin/ - адмін-панель (заборонена для індексації в robots.ts)
(marketing)/ - route group: усі нові SEO/контент-сторінки
layout.tsx - header/footer/рекламні слоти для цієї групи
about/, blog/, contact/, daily-challenge/, how-to-play/, leaderboard/,
multiplayer/, play-vs-ai/, play-vs-friend/, privacy/, terms/,
tic-tac-toe-rules/
sitemap.ts, robots.ts, manifest.ts, opengraph-image.tsx, icon.png, apple-icon.png
lib/
seo/ - site-config.ts (домен/бренд), metadata.ts (генератор Metadata),
json-ld.tsx (Organization/WebApplication/VideoGame/Breadcrumb/Article)
blog/posts.ts - дані статей блогу
i18n/ - locales.ts, get-dictionary.ts, dictionaries/{en,uk,de,es,fr,it,pt,nl,pl}.ts
components/
layout/ - SiteHeader, SiteFooter
ads/AdsManager.tsx - рекламні слоти (AdSense/NitroPay/Setupad/Mediavine)
analytics/ - GoogleAnalytics, GoogleTagManager
pwa/ - ServiceWorkerRegistration, InstallPrompt
social/ShareButtons.tsx
seo/Breadcrumbs.tsx
public/
sw.js - мінімальний service worker (офлайн-фолбек)
icons/ - згенеровані PNG-іконки (16/32/180/192/512)
Ігрові роути (/, /play, /play/[roomId], /admin) навмисно лишились
поза (marketing) route group і виглядають так само, як і раніше - нова
навігація/реклама на них не впливає.
.env.local:
NEXT_PUBLIC_AD_PROVIDER=adsense # adsense | nitropay | setupad | mediavine | none
.env.local):
NEXT_PUBLIC_ADSENSE_CLIENT, NEXT_PUBLIC_ADSENSE_SLOT_TOP /
_BOTTOM / _SIDEBAR / _INCONTENT.NEXT_PUBLIC_NITROPAY_SITE_ID.NEXT_PUBLIC_SETUPAD_PUBLISHER_ID.npm run dev / передеплойте.Розмітка сторінок не змінюється - <AdSlot position="..." />
(app/components/ads/AdsManager.tsx) сам вирішує, що рендерити, залежно від
NEXT_PUBLIC_AD_PROVIDER. Доступні позиції: top-banner, bottom-banner,
sidebar, between-content, reward. У dev-режимі без реального ID
показується пунктирний плейсхолдер із назвою позиції (щоб бачити верстку);
у production він просто не рендериться, поки немає реальних ID.
NEXT_PUBLIC_SITE_URL -> метод "HTML tag".content="..." і вставте в .env.local:
NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION=xxxxxxxxxxxxxxxx
<head> (див. verification.google
у app/layout.tsx).https://ваш-домен/sitemap.xml.NEXT_PUBLIC_ANALYTICS_ID=G-XXXXXXXXXX # GA4 Measurement ID
NEXT_PUBLIC_GTM_ID=GTM-XXXXXXX # GTM Container ID
Обидва підключаються лише якщо ID заданий (app/components/analytics/*) -
без ID жодних скриптів не вставляється. Можна використовувати одне з двох
або обидва одночасно.
i18n зараз - це готова структура з активною лише English, як і було погоджено на старті проєкту (переклад усього контенту на 5 мов вручну дав би непередбачувану якість без професійного перекладу).
Що вже є (app/lib/i18n/):
locales.ts - список з 9 мов (en, uk, de, es, fr, it, pt, nl, pl), en - дефолтна.dictionaries/{locale}.ts - короткі UI-рядки (навігація, футер, спільні
кнопки) вже перекладені для всіх 9 мов.app/lib/seo/translations.ts (правки - в адмінці, "Переклади" → SEO).Гра (game/src/lib/i18n.ts + locales/*.ts) уже працює всіма 9 мовами: мова береться з браузера
гравця (на порталі - з SDK), невідома мова - англійська. Правки текстів з адмінки ("Переклади")
лежать у Firestore translations/{locale} поверх вбудованих перекладів.
get-dictionary.ts - getDictionary(locale) асинхронно завантажує потрібний словник.Щоб перевести конкретну мову з "заготовки" в реально доступну (напр. /uk/...):
app/[locale]/ сегмент маршруту для сторінок, які мають
перекладатись (найпростіше - обгорнути лише (marketing) сторінки,
лишивши ігрові роути без префікса).getDictionary("en") на
getDictionary(params.locale).app/lib/blog/posts.ts, тексти
/how-to-play, /tic-tac-toe-rules тощо) - словники з dictionaries/
покривають лише UI-хром, не цей контент.alternates.languages (hreflang) у buildMetadata
(app/lib/seo/metadata.ts) для кожної активної мови.app/sitemap.ts.Щоб додати 7-у мову: створіть dictionaries/xx.ts (TypeScript провалить
збірку, якщо пропустите ключ - копіюйте en.ts і перекладіть значення),
додайте "xx" в locales і localeNames/localeToHreflang у locales.ts,
і зареєструйте в loaders у get-dictionary.ts.
app/components/gameLogic.ts /
app/components/onlineGameLogic.ts - нову логіку варто виносити так само
окремим модулем, а не в компонент.gameMode в
app/components/tic-tac-toe.tsx (за зразком "traditional" | "difficult")
і новий компонент на кшталт DifficultTicTacToe.OnlineGameMode
(app/components/onlineGameLogic.ts) і обробіть його в app/lib/onlineGame.ts
та OnlineBoard.tsx/FriendGameModal.tsx.app/(marketing)/ за зразком
play-vs-ai/page.tsx (метадані через buildMetadata, breadcrumbs, CTA на
реальний ігровий роут) і впишіть шлях в app/sitemap.ts.buildMetadata()
(app/lib/seo/metadata.ts) - єдине джерело title/description/keywords/canonical/OG/Twitter.app/lib/seo/json-ld.tsx - Organization + WebApplication
(глобально, в layout.tsx), VideoGame (на /play-vs-ai), BreadcrumbList
(у Breadcrumbs), BlogPosting (на сторінках блогу), FAQPage (на /tic-tac-toe-rules).app/sitemap.ts,
app/robots.ts) - офіційний App Router спосіб, нічого правити вручну.app/icon.png, app/apple-icon.png, app/manifest.ts,
public/icons/* згенеровані з public/images/logo.png. Це placeholder-якість
(масштабоване лого) - перед публікацією варто замінити на дизайнерські іконки.app/opengraph-image.tsx генерується динамічно через next/og.NEXT_PUBLIC_AD_PROVIDER=none і порожні NEXT_PUBLIC_ANALYTICS_ID/NEXT_PUBLIC_GTM_ID
означають, що жоден зовнішній рекламний/аналітичний скрипт не завантажується,
поки ви свідомо не заповните відповідні змінні середовища. Реальні рекламні
ID/домен/email у коді - лише плейсхолдери (tictactoe-game.com,
[email protected]) - замініть їх перед публікацією.
next.config.ts додає CSP, X-Frame-Options, X-Content-Type-Options,
Referrer-Policy, Permissions-Policy до кожної відповіді. CSP дозволяє лише
домени вже підключених інтеграцій (Firebase, Google Analytics/GTM, AdSense,
NitroPay). Якщо ви приберете styled-components або захочете прибрати
'unsafe-inline' зі script-src - перейдіть на nonce-based CSP
(generateNonce у next.config.ts).
next build), змінні середовища додайте в
Project Settings -> Environment Variables.output: "standalone" у next.config.ts.@cloudflare/next-on-pages (не входить у
цей проєкт) через відмінності edge-рантайму; app/opengraph-image.tsx
використовує export const runtime = "edge" і сумісний із цим шляхом./daily-challenge і /leaderboard - це SEO-сторінки з описом функціоналу
"Coming Soon", без реального бекенду (немає fake-даних, щоб не вводити в оману).