feat: enhance metadata, add robots and sitemap routes, and implement custom 404 and OpenGraph images

This commit is contained in:
Kewonit
2026-03-25 16:41:45 +05:30
parent 56b12afebe
commit 0e2ba9fc13
10 changed files with 548 additions and 21 deletions

View File

@ -53,9 +53,19 @@ const nextConfig: NextConfig = {
key: "Content-Security-Policy",
value: cspHeader.replace(/\s{2,}/g, " ").trim(),
},
{
key: "Strict-Transport-Security",
value: "max-age=63072000; includeSubDomains; preload",
},
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "X-Frame-Options", value: "DENY" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{ key: "X-DNS-Prefetch-Control", value: "on" },
{
key: "Permissions-Policy",
value:
"camera=(), microphone=(), geolocation=(self), interest-cohort=()",
},
],
},
{

BIN
public/aeris-hero.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 396 KiB

View File

@ -14,25 +14,43 @@ const GA_ID = process.env.NEXT_PUBLIC_GA_ID;
const title = "Aeris — Real-Time 3D Flight Tracking";
const description =
"Track live flights in 3D over the world's busiest airspaces. Altitude-aware, beautifully rendered, and completely free.";
"Track live flights in stunning 3D over the world's busiest airspaces. See real-time ADS-B data with altitude-aware rendering — low altitudes glow cyan, high altitudes shift to gold. Free and open source.";
const siteUrl = "https://aeris.edbn.me";
export const metadata: Metadata = {
title,
description,
metadataBase: new URL(siteUrl),
title: {
default: title,
template: "%s | Aeris",
},
description,
applicationName: "Aeris",
keywords: [
"flight tracker",
"live flights",
"live flight tracker",
"3D flight tracking",
"real-time aviation",
"real-time flight tracker",
"flight radar",
"aircraft tracking",
"aeris",
"opensky",
"aircraft tracker",
"plane tracker",
"ADS-B tracker",
"live aircraft map",
"flight tracking map",
"airplane tracker live",
"aviation tracker",
"track flights live",
"free flight tracker",
"aeris flight tracker",
"opensky network",
"airplanes live",
"adsb tracker",
"live air traffic",
"flight path tracker",
],
authors: [{ name: "kewonit", url: "https://github.com/kewonit" }],
creator: "kewonit",
publisher: "kewonit",
category: "travel",
openGraph: {
type: "website",
locale: "en_US",
@ -49,9 +67,25 @@ export const metadata: Metadata = {
robots: {
index: true,
follow: true,
googleBot: { index: true, follow: true },
nocache: false,
googleBot: {
index: true,
follow: true,
"max-video-preview": -1,
"max-image-preview": "large",
"max-snippet": -1,
},
},
alternates: { canonical: siteUrl },
icons: {
icon: "/favicon.ico",
},
other: {
"mobile-web-app-capable": "yes",
"apple-mobile-web-app-capable": "yes",
"apple-mobile-web-app-status-bar-style": "black-translucent",
"apple-mobile-web-app-title": "Aeris",
},
};
export default function RootLayout({

22
src/app/manifest.ts Normal file
View File

@ -0,0 +1,22 @@
import type { MetadataRoute } from "next";
export default function manifest(): MetadataRoute.Manifest {
return {
name: "Aeris — Real-Time 3D Flight Tracking",
short_name: "Aeris",
description:
"Track live flights in 3D over the world's busiest airspaces. Altitude-aware, beautifully rendered, and completely free.",
start_url: "/",
display: "standalone",
background_color: "#000000",
theme_color: "#000000",
icons: [
{
src: "/favicon.ico",
sizes: "any",
type: "image/x-icon",
},
],
categories: ["travel", "navigation", "utilities"],
};
}

73
src/app/not-found.tsx Normal file
View File

@ -0,0 +1,73 @@
import type { Metadata } from "next";
import Link from "next/link";
export const metadata: Metadata = {
title: "Page Not Found",
description:
"The page you are looking for does not exist. Return to Aeris to track live flights in 3D.",
};
export default function NotFound() {
return (
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
minHeight: "100dvh",
background: "hsl(0 0% 0%)",
color: "hsl(0 0% 100%)",
fontFamily: "Inter, system-ui, sans-serif",
textAlign: "center",
padding: "2rem",
}}
>
<h1
style={{
fontSize: "6rem",
fontWeight: 700,
margin: 0,
letterSpacing: "-2px",
opacity: 0.15,
}}
>
404
</h1>
<h2
style={{
fontSize: "1.5rem",
fontWeight: 600,
margin: "0.5rem 0",
}}
>
Page not found
</h2>
<p
style={{
fontSize: "1rem",
color: "hsl(0 0% 60%)",
maxWidth: "28rem",
marginTop: "0.5rem",
}}
>
The page you&apos;re looking for doesn&apos;t exist or has been moved.
</p>
<Link
href="/"
style={{
marginTop: "2rem",
padding: "0.75rem 2rem",
borderRadius: "0.5rem",
background: "hsl(0 0% 100%)",
color: "hsl(0 0% 0%)",
fontSize: "0.875rem",
fontWeight: 600,
textDecoration: "none",
}}
>
Back to Aeris
</Link>
</div>
);
}

148
src/app/opengraph-image.tsx Normal file
View File

@ -0,0 +1,148 @@
import { ImageResponse } from "next/og";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
export const alt = "Aeris — Real-Time 3D Flight Tracking";
export const size = { width: 1200, height: 630 };
export const contentType = "image/png";
export default async function Image() {
const imageData = await readFile(
join(process.cwd(), "public", "aeris-hero.png"),
);
const base64 = imageData.toString("base64");
const heroSrc = `data:image/png;base64,${base64}`;
return new ImageResponse(
<div
style={{
width: "100%",
height: "100%",
display: "flex",
position: "relative",
overflow: "hidden",
fontFamily: "Inter, system-ui, sans-serif",
}}
>
{/* Hero background image */}
<img
src={heroSrc}
alt=""
width={1200}
height={630}
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
objectFit: "cover",
}}
/>
{/* Full dark vignette overlay */}
<div
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
background:
"linear-gradient(to top right, rgba(0,0,0,0.95) 0%, rgba(0,0,0,0.7) 25%, rgba(0,0,0,0.15) 50%, rgba(0,0,0,0.05) 100%)",
display: "flex",
}}
/>
{/* Content overlay pinned to bottom */}
<div
style={{
position: "absolute",
bottom: 0,
left: 0,
width: "100%",
padding: "0 60px 44px 60px",
display: "flex",
flexDirection: "column",
}}
>
{/* Title */}
<div
style={{
fontSize: "56px",
fontWeight: 700,
color: "#ffffff",
letterSpacing: "-1.5px",
lineHeight: 1,
display: "flex",
}}
>
Aeris
</div>
{/* Tagline */}
<div
style={{
fontSize: "24px",
fontWeight: 400,
color: "rgba(255,255,255,0.85)",
marginTop: "10px",
display: "flex",
}}
>
Real-Time 3D Flight Tracking
</div>
{/* Divider + pills row */}
<div
style={{
display: "flex",
alignItems: "center",
gap: "12px",
marginTop: "20px",
}}
>
{["Altitude-Aware", "Live ADS-B Data", "Free & Open Source"].map(
(label) => (
<div
key={label}
style={{
padding: "6px 18px",
borderRadius: "100px",
background: "rgba(0,0,0,0.75)",
border: "1px solid rgba(255,255,255,0.18)",
color: "rgba(255,255,255,0.85)",
fontSize: "14px",
fontWeight: 500,
display: "flex",
}}
>
{label}
</div>
),
)}
</div>
</div>
{/* URL badge top-right */}
<div
style={{
position: "absolute",
top: "48px",
right: "56px",
fontSize: "15px",
fontWeight: 600,
color: "rgba(255,255,255,0.9)",
display: "flex",
padding: "8px 18px",
borderRadius: "100px",
background: "rgba(0,0,0,0.65)",
border: "1px solid rgba(255,255,255,0.2)",
}}
>
aeris.edbn.me
</div>
</div>,
{ ...size },
);
}

View File

@ -1,17 +1,83 @@
import { FlightTracker } from "@/components/flight-tracker";
const jsonLd = {
"@context": "https://schema.org",
"@type": "WebApplication",
name: "Aeris",
url: "https://aeris.edbn.me",
description:
"Track live flights in 3D over the world's busiest airspaces. Altitude-aware, beautifully rendered, and completely free.",
applicationCategory: "TravelApplication",
operatingSystem: "Any",
offers: { "@type": "Offer", price: "0", priceCurrency: "USD" },
author: { "@type": "Person", name: "kewonit" },
};
const siteUrl = "https://aeris.edbn.me";
const jsonLd = [
{
"@context": "https://schema.org",
"@type": "WebApplication",
"@id": `${siteUrl}/#app`,
name: "Aeris",
url: siteUrl,
description:
"Track live flights in stunning 3D over the world's busiest airspaces. See real-time ADS-B data with altitude-aware rendering — low altitudes glow cyan, high altitudes shift to gold. Free and open source.",
applicationCategory: "TravelApplication",
operatingSystem: "Any",
browserRequirements: "Requires WebGL support",
offers: {
"@type": "Offer",
price: "0",
priceCurrency: "USD",
availability: "https://schema.org/OnlineOnly",
},
author: {
"@type": "Person",
name: "kewonit",
url: "https://github.com/kewonit",
},
featureList: [
"Real-time 3D flight tracking",
"Altitude-aware color rendering",
"Live ADS-B data from multiple sources",
"3D aircraft models",
"City-based airspace views",
"Live ATC audio streaming",
"Flight trail visualization",
"Aircraft photo lookup",
"Dark mode interface",
],
screenshot:
"https://github.com/user-attachments/assets/9d1f50ed-be4e-4ef5-95ac-257e9129f8c8",
softwareVersion: "0.1.0",
isAccessibleForFree: true,
inLanguage: "en",
},
{
"@context": "https://schema.org",
"@type": "WebSite",
"@id": `${siteUrl}/#website`,
name: "Aeris",
url: siteUrl,
description:
"Real-time 3D flight tracking — altitude-aware, visually stunning, and completely free.",
inLanguage: "en",
publisher: {
"@type": "Person",
name: "kewonit",
url: "https://github.com/kewonit",
},
potentialAction: {
"@type": "SearchAction",
target: {
"@type": "EntryPoint",
urlTemplate: `${siteUrl}/?q={search_term_string}`,
},
"query-input": "required name=search_term_string",
},
},
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: [
{
"@type": "ListItem",
position: 1,
name: "Aeris — Real-Time 3D Flight Tracking",
item: siteUrl,
},
],
},
];
export default function Home() {
return (

14
src/app/robots.ts Normal file
View File

@ -0,0 +1,14 @@
import type { MetadataRoute } from "next";
export default function robots(): MetadataRoute.Robots {
return {
rules: [
{
userAgent: "*",
allow: "/",
disallow: ["/api/", "/private/"],
},
],
sitemap: "https://aeris.edbn.me/sitemap.xml",
};
}

12
src/app/sitemap.ts Normal file
View File

@ -0,0 +1,12 @@
import type { MetadataRoute } from "next";
export default function sitemap(): MetadataRoute.Sitemap {
return [
{
url: "https://aeris.edbn.me",
lastModified: new Date(),
changeFrequency: "daily",
priority: 1,
},
];
}

148
src/app/twitter-image.tsx Normal file
View File

@ -0,0 +1,148 @@
import { ImageResponse } from "next/og";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
export const alt = "Aeris — Real-Time 3D Flight Tracking";
export const size = { width: 1200, height: 630 };
export const contentType = "image/png";
export default async function Image() {
const imageData = await readFile(
join(process.cwd(), "public", "aeris-hero.png"),
);
const base64 = imageData.toString("base64");
const heroSrc = `data:image/png;base64,${base64}`;
return new ImageResponse(
<div
style={{
width: "100%",
height: "100%",
display: "flex",
position: "relative",
overflow: "hidden",
fontFamily: "Inter, system-ui, sans-serif",
}}
>
{/* Hero background image */}
<img
src={heroSrc}
alt=""
width={1200}
height={630}
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
objectFit: "cover",
}}
/>
{/* Full dark vignette overlay */}
<div
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
background:
"linear-gradient(to top right, rgba(0,0,0,0.95) 0%, rgba(0,0,0,0.7) 25%, rgba(0,0,0,0.15) 50%, rgba(0,0,0,0.05) 100%)",
display: "flex",
}}
/>
{/* Content overlay pinned to bottom */}
<div
style={{
position: "absolute",
bottom: 0,
left: 0,
width: "100%",
padding: "0 60px 44px 60px",
display: "flex",
flexDirection: "column",
}}
>
{/* Title */}
<div
style={{
fontSize: "56px",
fontWeight: 700,
color: "#ffffff",
letterSpacing: "-1.5px",
lineHeight: 1,
display: "flex",
}}
>
Aeris
</div>
{/* Tagline */}
<div
style={{
fontSize: "24px",
fontWeight: 400,
color: "rgba(255,255,255,0.85)",
marginTop: "10px",
display: "flex",
}}
>
Real-Time 3D Flight Tracking
</div>
{/* Divider + pills row */}
<div
style={{
display: "flex",
alignItems: "center",
gap: "12px",
marginTop: "20px",
}}
>
{["Altitude-Aware", "Live ADS-B Data", "Free & Open Source"].map(
(label) => (
<div
key={label}
style={{
padding: "6px 18px",
borderRadius: "100px",
background: "rgba(0,0,0,0.75)",
border: "1px solid rgba(255,255,255,0.18)",
color: "rgba(255,255,255,0.85)",
fontSize: "14px",
fontWeight: 500,
display: "flex",
}}
>
{label}
</div>
),
)}
</div>
</div>
{/* URL badge top-right */}
<div
style={{
position: "absolute",
top: "48px",
right: "56px",
fontSize: "15px",
fontWeight: 600,
color: "rgba(255,255,255,0.9)",
display: "flex",
padding: "8px 18px",
borderRadius: "100px",
background: "rgba(0,0,0,0.65)",
border: "1px solid rgba(255,255,255,0.2)",
}}
>
aeris.edbn.me
</div>
</div>,
{ ...size },
);
}