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-даних, щоб не вводити в оману).