diff --git a/next.config.ts b/next.config.ts index 395e952..7c57f80 100644 --- a/next.config.ts +++ b/next.config.ts @@ -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=()", + }, ], }, { diff --git a/public/aeris-hero.png b/public/aeris-hero.png new file mode 100644 index 0000000..e186de9 Binary files /dev/null and b/public/aeris-hero.png differ diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 8e854ce..a30e9f4 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -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({ diff --git a/src/app/manifest.ts b/src/app/manifest.ts new file mode 100644 index 0000000..d401692 --- /dev/null +++ b/src/app/manifest.ts @@ -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"], + }; +} diff --git a/src/app/not-found.tsx b/src/app/not-found.tsx new file mode 100644 index 0000000..2129a34 --- /dev/null +++ b/src/app/not-found.tsx @@ -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 ( +
+

+ 404 +

+

+ Page not found +

+

+ The page you're looking for doesn't exist or has been moved. +

+ + Back to Aeris + +
+ ); +} diff --git a/src/app/opengraph-image.tsx b/src/app/opengraph-image.tsx new file mode 100644 index 0000000..96583c9 --- /dev/null +++ b/src/app/opengraph-image.tsx @@ -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( +
+ {/* Hero background image */} + + + {/* Full dark vignette overlay */} +
+ + {/* Content overlay pinned to bottom */} +
+ {/* Title */} +
+ Aeris +
+ + {/* Tagline */} +
+ Real-Time 3D Flight Tracking +
+ + {/* Divider + pills row */} +
+ {["Altitude-Aware", "Live ADS-B Data", "Free & Open Source"].map( + (label) => ( +
+ {label} +
+ ), + )} +
+
+ + {/* URL badge top-right */} +
+ aeris.edbn.me +
+
, + { ...size }, + ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx index 9349e85..ddd4cc9 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -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 ( diff --git a/src/app/robots.ts b/src/app/robots.ts new file mode 100644 index 0000000..fa3cbd8 --- /dev/null +++ b/src/app/robots.ts @@ -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", + }; +} diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts new file mode 100644 index 0000000..48a17cd --- /dev/null +++ b/src/app/sitemap.ts @@ -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, + }, + ]; +} diff --git a/src/app/twitter-image.tsx b/src/app/twitter-image.tsx new file mode 100644 index 0000000..96583c9 --- /dev/null +++ b/src/app/twitter-image.tsx @@ -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( +
+ {/* Hero background image */} + + + {/* Full dark vignette overlay */} +
+ + {/* Content overlay pinned to bottom */} +
+ {/* Title */} +
+ Aeris +
+ + {/* Tagline */} +
+ Real-Time 3D Flight Tracking +
+ + {/* Divider + pills row */} +
+ {["Altitude-Aware", "Live ADS-B Data", "Free & Open Source"].map( + (label) => ( +
+ {label} +
+ ), + )} +
+
+ + {/* URL badge top-right */} +
+ aeris.edbn.me +
+
, + { ...size }, + ); +}