diff --git a/website/README.md b/website/README.md index a2243356..0a06e6c5 100644 --- a/website/README.md +++ b/website/README.md @@ -9,7 +9,14 @@ Next.js landing page (`website/`). The playable app lives in `frontend/`. pnpm dev:web ``` -Copy `env.example` to `.env.local` and set `NEXT_PUBLIC_APP_URL` to your local or deployed app URL. +Copy `env.example` to `.env.local` and set: + +- `NEXT_PUBLIC_APP_URL` — the local or deployed **app** URL, used by the "Play Now" CTA. +- `NEXT_PUBLIC_SITE_URL` — the public origin of **this site**, used for canonical + URLs, `sitemap.xml`, `robots.txt` and Open Graph tags. It defaults to + `http://localhost:3002`, so a production deploy that leaves it unset publishes a + canonical tag and sitemap pointing at localhost. The two are different domains; + do not reuse `NEXT_PUBLIC_APP_URL` here. ## Deploy to Vercel (GitHub Actions) @@ -43,6 +50,7 @@ CI runs `vercel pull` / `vercel deploy` from the monorepo root so `pnpm-lock.yam | `VERCEL_ORG_ID` | Secret | Team/user ID | | `VERCEL_WEBSITE_PROJECT_ID` | Secret | This website project’s ID | | `NEXT_PUBLIC_APP_URL` | Variable | Public URL of the `frontend` app | +| `NEXT_PUBLIC_SITE_URL` | Variable | Public URL of this marketing site (canonical, sitemap, OG) | Workflow: none. `.github/workflows/website.yml` was removed in 49c5e63, and the secrets table above plus the triggers below describe that workflow. They have diff --git a/website/env.example b/website/env.example index 6762e415..974cbbdb 100644 --- a/website/env.example +++ b/website/env.example @@ -1,2 +1,7 @@ -# URL of the deployed Crypto Pets app (frontend) — used by the landing "Start Playing" CTA +# URL of the deployed Crypto Pets app (frontend) — used by the landing "Play Now" CTA NEXT_PUBLIC_APP_URL=http://localhost:5173 + +# Public origin of THIS marketing site — used for canonical URLs, sitemap.xml, +# robots.txt and Open Graph tags. Must be set in production, or crawlers are +# handed localhost. Not the same as NEXT_PUBLIC_APP_URL above. +NEXT_PUBLIC_SITE_URL=http://localhost:3002 diff --git a/website/public/images/pets/cat.png b/website/public/images/pets/cat.png deleted file mode 100644 index f352c0ba..00000000 Binary files a/website/public/images/pets/cat.png and /dev/null differ diff --git a/website/public/images/pets/cinder-streak.png b/website/public/images/pets/cinder-streak.png new file mode 100644 index 00000000..ec7872d9 Binary files /dev/null and b/website/public/images/pets/cinder-streak.png differ diff --git a/website/public/images/pets/dinosaur.png b/website/public/images/pets/dinosaur.png deleted file mode 100644 index b920ca39..00000000 Binary files a/website/public/images/pets/dinosaur.png and /dev/null differ diff --git a/website/public/images/pets/dog.png b/website/public/images/pets/dog.png deleted file mode 100644 index c6d1ce7c..00000000 Binary files a/website/public/images/pets/dog.png and /dev/null differ diff --git a/website/public/images/pets/elephant.png b/website/public/images/pets/elephant.png deleted file mode 100644 index bf9d5c72..00000000 Binary files a/website/public/images/pets/elephant.png and /dev/null differ diff --git a/website/public/images/pets/ember-oracle.png b/website/public/images/pets/ember-oracle.png new file mode 100644 index 00000000..384ba664 Binary files /dev/null and b/website/public/images/pets/ember-oracle.png differ diff --git a/website/public/images/pets/lion.png b/website/public/images/pets/lion.png deleted file mode 100644 index 4a8a057b..00000000 Binary files a/website/public/images/pets/lion.png and /dev/null differ diff --git a/website/public/images/pets/nova-brute.png b/website/public/images/pets/nova-brute.png new file mode 100644 index 00000000..27b619b8 Binary files /dev/null and b/website/public/images/pets/nova-brute.png differ diff --git a/website/public/images/pets/owl.png b/website/public/images/pets/owl.png deleted file mode 100644 index 14894515..00000000 Binary files a/website/public/images/pets/owl.png and /dev/null differ diff --git a/website/public/images/pets/starlit-prowler.png b/website/public/images/pets/starlit-prowler.png new file mode 100644 index 00000000..158984ac Binary files /dev/null and b/website/public/images/pets/starlit-prowler.png differ diff --git a/website/public/images/pets/tidefang.png b/website/public/images/pets/tidefang.png new file mode 100644 index 00000000..426535f6 Binary files /dev/null and b/website/public/images/pets/tidefang.png differ diff --git a/website/public/images/pets/umbral-bulwark.png b/website/public/images/pets/umbral-bulwark.png new file mode 100644 index 00000000..b93c8743 Binary files /dev/null and b/website/public/images/pets/umbral-bulwark.png differ diff --git a/website/public/llms.txt b/website/public/llms.txt index f8117313..fe0a1816 100644 --- a/website/public/llms.txt +++ b/website/public/llms.txt @@ -1,25 +1,48 @@ # CryptoPets -> A fully on-chain creature collection and battle game. Mint, breed, train, and -> battle pet NFTs across Ethereum and Solana — playable on web and mobile. +> A creature collection and battle game where the pets are NFTs. Mint, breed, +> train and battle across Ethereum and Solana — on web and mobile. This is the marketing landing site. The playable app lives at a separate URL -(see Links). Pets are NFTs held in the player's own wallet — mintable, tradable, -and transferable independent of the app. +(see Links). Pets and items are NFTs held in the player's own wallet — mintable, +tradable, and transferable independent of the app. ## Overview -- **What it is:** on-chain pet collection + tactical battle game (NFTs). -- **Chains:** Ethereum and Solana, with additional rollups planned through Q3. -- **Wallets:** MetaMask, Phantom, or social login. +- **What it is:** on-chain pet collection and tactical battle game (NFTs). +- **Chains:** Ethereum and Solana. Pets, breeding and battles run on both; + equipment and item NFTs are on Ethereum today. +- **Wallets:** MetaMask on Ethereum, Phantom on Solana. - **Platforms:** web and mobile. ## Gameplay -- **Connect** any wallet (MetaMask, Phantom, social login). -- **Mint** a pet from the egg pool and roll for a rare trait. -- **Train** — level up, breed new bloodlines, unlock signature abilities. -- **Battle** rivals in the arena and climb the global leaderboard. +- **Connect** the wallet you already have. +- **Hatch** a starter pet whose traits come from on-chain randomness. +- **Raise** it — level up, train stats, equip gear, breed bloodlines, marry a + partner pet (which unlocks a private thread between the two owners). +- **Battle** rivals in the arena and climb the season leaderboard. + +## Provably fair battles + +- Defending requires a wallet-signed authorization naming the pet, the level band, + the exact rule set, a validity window and a daily cap. A pet cannot be dragged + into a fight its owner did not agree to. +- Each battle is seeded from a public randomness beacon round committed **before** + the fight resolves, so no party can grind the roll. +- Every result is a signed receipt over the exact inputs it used, and batches of + receipts are committed to a Merkle root written on chain. +- An open-source verifier replays any receipt independently and reports seven + checks separately: seed derivation, operator signature, beacon signature, + combat replay, progression, equipment and hash-chain continuity. It needs no + account and no access to the project's servers. + +## Rewards + +- Seasons pay CPET to the top of the leaderboard, claimed against an on-chain + Merkle root with per-wallet and per-season ceilings. +- CPET has a fixed supply and no mint function, so the total is checkable by + anyone and cannot be inflated later. ## Rarity tiers @@ -30,24 +53,35 @@ and transferable independent of the app. ## Roadmap -- Q1 — Genesis Drop (shipped): genesis mint, socials, first 10k supply. -- Q2 — Arena (shipped): battle system v1, leaderboards, weekly tournaments. -- Q3 — Bloodlines (in progress): breeding, cross-chain support, new rarity tier. -- Q4 — Marketplace 2.0 (planned): native P2P trades, mobile app, guild system. +Phases, not dates. + +- 01 Foundation (shipped): dual-chain minting, breeding and bloodlines, marriage, + level up, train, rename, transfer. +- 02 Provable Arena (shipped): beacon-seeded battles, signed and chain-anchored + receipts, open-source public verifier. +- 03 Progression (in progress): leaderboard and seasons, CPET season rewards, + equipment and item NFTs. +- 04 Expansion (planned): daily quests, team battles, pet and item marketplace. + +## Built with + +Ethereum, Solana, Base, Pyth Entropy, Switchboard, drand, Metaplex, The Graph. ## Links - [Play the app](https://cryptopets.vercel.app) - [Source code (GitHub)](https://github.com/radcrew/do-not-stop) -- [Features](/#features) +- [Receipt verifier](https://github.com/radcrew/do-not-stop/tree/main/verifier) - [How to play](/#how) +- [Features](/#features) - [Pets](/#pets) +- [Provably fair](/#proof) - [Roadmap](/#roadmap) - [FAQ](/#faq) -## Optional +## Notes -- Contracts are independently audited; audit reports are linked in the docs and - updated on every major release. - Connecting a wallet is free; mint price varies per drop and is announced ahead - of time on community channels (Discord, Twitter). + of time on community channels. +- Pets and items are tradable assets and seasons pay rewards to the top of the + leaderboard. This is a game you own a piece of, not an income stream. diff --git a/website/src/app/layout.tsx b/website/src/app/layout.tsx index dd9a2e25..c49026b1 100644 --- a/website/src/app/layout.tsx +++ b/website/src/app/layout.tsx @@ -2,6 +2,7 @@ import type { Metadata } from 'next'; import type { ReactNode } from 'react'; import { Inter, Orbitron } from 'next/font/google'; +import { SITE_URL } from '@/lib/siteUrl'; import '../styles/globals.css'; const orbitron = Orbitron({ @@ -17,14 +18,67 @@ const inter = Inter({ display: 'swap', }); +const TITLE = 'Crypto Pets'; +const DESCRIPTION = + 'Collect, breed and battle NFT pets on Ethereum and Solana. Every battle settles from a committed seed and ships with a receipt anyone can replay.'; + export const metadata: Metadata = { - title: 'Crypto Pets', - description: 'Collect, battle and breed unique on-chain pets in the ultimate Crypto Pets adventure.', + // Required for Next to resolve the relative URLs below into absolute ones. + metadataBase: new URL(SITE_URL), + title: { + default: TITLE, + template: '%s · Crypto Pets', + }, + description: DESCRIPTION, + applicationName: 'Crypto Pets', + keywords: [ + 'NFT game', + 'on-chain game', + 'pet battler', + 'Ethereum', + 'Solana', + 'provably fair', + 'blockchain gaming', + ], + alternates: { canonical: '/' }, + openGraph: { + type: 'website', + url: '/', + siteName: 'Crypto Pets', + title: TITLE, + description: DESCRIPTION, + locale: 'en_US', + }, + twitter: { + card: 'summary_large_image', + title: TITLE, + description: DESCRIPTION, + }, + robots: { + index: true, + follow: true, + googleBot: { index: true, follow: true, 'max-image-preview': 'large' }, + }, }; +/* Runs before first paint. Reveal targets start hidden only once this class is + present, so a blocked or failed bundle degrades to a fully visible page + instead of a blank one below the fold. */ +const REVEAL_GUARD = "document.documentElement.classList.add('js-reveal')"; + export default function RootLayout({ children }: { children: ReactNode }) { return ( - + /* The guard above mutates this element's class list before React hydrates, + so the server markup and the client tree disagree on className by design. + Without this, that shows up as a hydration mismatch on every load. */ + + +