diff --git a/package-lock.json b/package-lock.json index 333c396..9881e26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@types/serialize-javascript": "^5.0.4", "@vercel/analytics": "^1.6.1", "@vercel/edge-config": "^1.4.3", + "canvas-confetti": "^1.9.4", "chart.js": "^4.5.1", "embla-carousel-react": "8.6.0", "js-sha1": "^0.7.0", @@ -45,6 +46,7 @@ "devDependencies": { "@tailwindcss/postcss": "^4", "@tailwindcss/typography": "^0.5.19", + "@types/canvas-confetti": "^1.9.0", "@types/mjml": "^5.0.0", "@types/mjml-core": "^5.0.0", "@types/node": "^20", @@ -2779,6 +2781,13 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@types/canvas-confetti": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@types/canvas-confetti/-/canvas-confetti-1.9.0.tgz", + "integrity": "sha512-aBGj/dULrimR1XDZLtG9JwxX1b4HPRF6CX9Yfwh3NvstZEm1ZL7RBnel4keCPSqs1ANRu1u2Aoz9R+VmtjYuTg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -3628,6 +3637,16 @@ ], "license": "CC-BY-4.0" }, + "node_modules/canvas-confetti": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.4.tgz", + "integrity": "sha512-yxQbJkAVrFXWNbTUjPqjF7G+g6pDotOUHGbkZq2NELZUMDpiJ85rIEazVb8GTaAptNW2miJAXbs1BtioA251Pw==", + "license": "ISC", + "funding": { + "type": "donate", + "url": "https://www.paypal.me/kirilvatev" + } + }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", diff --git a/package.json b/package.json index d220ffa..7d6ebc1 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@types/serialize-javascript": "^5.0.4", "@vercel/analytics": "^1.6.1", "@vercel/edge-config": "^1.4.3", + "canvas-confetti": "^1.9.4", "chart.js": "^4.5.1", "embla-carousel-react": "8.6.0", "js-sha1": "^0.7.0", @@ -46,6 +47,7 @@ "devDependencies": { "@tailwindcss/postcss": "^4", "@tailwindcss/typography": "^0.5.19", + "@types/canvas-confetti": "^1.9.0", "@types/mjml": "^5.0.0", "@types/mjml-core": "^5.0.0", "@types/node": "^20", diff --git a/public/homepage/celias-stupid-romhack.gif b/public/homepage/celias-stupid-romhack.gif new file mode 100644 index 0000000..90a9e7b Binary files /dev/null and b/public/homepage/celias-stupid-romhack.gif differ diff --git a/public/homepage/emerald-rogue.png b/public/homepage/emerald-rogue.png new file mode 100644 index 0000000..781d250 Binary files /dev/null and b/public/homepage/emerald-rogue.png differ diff --git a/public/homepage/pokemon-crystal-advance-redux.png b/public/homepage/pokemon-crystal-advance-redux.png new file mode 100644 index 0000000..6c97b3f Binary files /dev/null and b/public/homepage/pokemon-crystal-advance-redux.png differ diff --git a/public/homepage/pokemon-odyssey.png b/public/homepage/pokemon-odyssey.png new file mode 100644 index 0000000..5a60801 Binary files /dev/null and b/public/homepage/pokemon-odyssey.png differ diff --git a/public/homepage/pokemon-rowe.png b/public/homepage/pokemon-rowe.png new file mode 100644 index 0000000..b5ce08f Binary files /dev/null and b/public/homepage/pokemon-rowe.png differ diff --git a/public/homepage/pokemon-unbound.png b/public/homepage/pokemon-unbound.png new file mode 100644 index 0000000..382cf2f Binary files /dev/null and b/public/homepage/pokemon-unbound.png differ diff --git a/public/homepage/super-mariomon.png b/public/homepage/super-mariomon.png new file mode 100644 index 0000000..aa6a2c2 Binary files /dev/null and b/public/homepage/super-mariomon.png differ diff --git a/public/homepage/sword-and-shield-ultimate-plus.png b/public/homepage/sword-and-shield-ultimate-plus.png new file mode 100644 index 0000000..0c7a558 Binary files /dev/null and b/public/homepage/sword-and-shield-ultimate-plus.png differ diff --git a/public/homepage/too-many-types-2.png b/public/homepage/too-many-types-2.png new file mode 100644 index 0000000..2171bdd Binary files /dev/null and b/public/homepage/too-many-types-2.png differ diff --git a/src/app/globals.css b/src/app/globals.css index d7ef435..95cb9de 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -102,6 +102,23 @@ html { scroll-padding-top: var(--anchor-offset); } border: 1px solid var(--border); border-radius: 12px; } + +/* Interpolatable ready-ring for homepage hero hack cards (Tailwind ring-* does not transition cleanly) */ +.hero-hack-card { + box-shadow: 0 0 0 1px var(--border); + transition: box-shadow 500ms ease; +} +.hero-hack-card[data-ready="true"] { + box-shadow: 0 0 0 1px rgb(52 211 153 / 0.5); /* emerald-400/50 */ +} + +@keyframes heroHackFadeIn { + from { opacity: 0; } + to { opacity: 1; } +} +.hero-hack-image { + animation: heroHackFadeIn 500ms ease forwards; +} .card-simple { background: var(--surface-2); border: 1px solid var(--border); @@ -157,6 +174,25 @@ html { scroll-padding-top: var(--anchor-offset); } .anim-pulse { animation: pulseSoft 2.4s ease-in-out infinite; } .anim-pop { animation: popIn 220ms cubic-bezier(0.16, 1, 0.3, 1); } +@keyframes heroConnectorDash { + to { stroke-dashoffset: -24; } +} + +.hero-connector-path { + stroke-dasharray: 6 6; + animation: heroConnectorDash 1.2s linear infinite; +} + +@media (prefers-reduced-motion: reduce) { + .anim-float, + .anim-pulse, + .anim-pop, + .hero-connector-path, + .hero-hack-image { + animation: none !important; + } +} + .shine-wrap { position: relative; overflow: hidden; border-radius: inherit; } .shine-wrap::after { content: ""; diff --git a/src/app/page.tsx b/src/app/page.tsx index a454f14..00a43f2 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -4,6 +4,9 @@ import { FaArrowRightLong } from "react-icons/fa6"; import { createClient } from "@/utils/supabase/server"; import HackCard from "@/components/HackCard"; import Button from "@/components/Button"; +import MilestoneCelebration from "@/components/Home/MilestoneCelebration"; +import HeroPatchDiagram from "@/components/Home/HeroPatchDiagram"; +import HeroAuthCta from "@/components/Home/HeroAuthCta"; import { sortOrderedTags, getCoverUrls } from "@/utils/format"; import { HackCardAttributes } from "@/components/HackCard"; import { resolveHackDisplayVersion } from "@/utils/patches/hack-display-version"; @@ -146,51 +149,77 @@ export default async function Home() {
-
-
-

- Discover and share Pokémon romhacks -

-

- Find community-made hacks and patch in-browser with your own legally-obtained base ROMs for Game Boy, Game Boy Color, Game Boy Advance, and Nintendo DS. -

-
- - Explore hacks - - - Submit a patch - - - Already a creator? Log in - +
+
+
+ +

+ Bring your ROM once. +
+ Play everything it unlocks. +

+

+ Link your legally-obtained base ROM one time and Hackdex caches it on your + device. Patch any Pokémon ROM hack built for it, right in your browser, + without ever re-uploading. Your files never leave your device. +

+
+ + Explore hacks + + + Submit a patch + + +
+

+ Supports Game Boy, Game Boy Color, Game Boy Advance, and Nintendo DS. +

+
0 ? "pt-6 sm:pt-12" : "py-6 sm:py-12"}`}> -
-
-
Curated discovery
-

Browse popular and trending patches across generations.

+

How it works

+
+