Compare commits
10 Commits
5125107d5b
...
a246765884
| Author | SHA1 | Date | |
|---|---|---|---|
| a246765884 | |||
| 498504b73b | |||
| 0e2ba9fc13 | |||
| 56b12afebe | |||
| eb1103f63f | |||
| 147b69b944 | |||
| 3a10da0486 | |||
| a08f1c7250 | |||
| e262bd730d | |||
| bf99d4843f |
27
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Report a reproducible problem
|
||||||
|
labels: bug
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
Describe the issue clearly.
|
||||||
|
|
||||||
|
## Steps to Reproduce
|
||||||
|
1.
|
||||||
|
2.
|
||||||
|
3.
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
What should happen.
|
||||||
|
|
||||||
|
## Actual Behavior
|
||||||
|
What happened instead.
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
- OS:
|
||||||
|
- Browser/Version:
|
||||||
|
- Commit/Branch:
|
||||||
|
|
||||||
|
## Additional Context
|
||||||
|
Logs, screenshots, or other details.
|
||||||
2
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links: []
|
||||||
21
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
name: Feature request
|
||||||
|
about: Propose an enhancement
|
||||||
|
labels: enhancement
|
||||||
|
---
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
What problem should this solve?
|
||||||
|
|
||||||
|
## Proposal
|
||||||
|
Describe the proposed solution.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
What is in scope and out of scope?
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
- [ ]
|
||||||
|
- [ ]
|
||||||
|
|
||||||
|
## Additional Context
|
||||||
|
Related links, references, or constraints.
|
||||||
15
.github/SECURITY.md
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
The `main` branch is the supported baseline for security fixes.
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
Please do not disclose vulnerabilities publicly.
|
||||||
|
|
||||||
|
Report security issues privately to the maintainers with:
|
||||||
|
- A clear description of the issue
|
||||||
|
- Steps to reproduce
|
||||||
|
- Impact assessment
|
||||||
|
- Any suggested mitigation
|
||||||
|
|
||||||
|
We will acknowledge valid reports and provide status updates during triage and remediation.
|
||||||
15
.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
## Summary
|
||||||
|
Describe what changed and why.
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
-
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
- [ ] Relevant checks pass
|
||||||
|
- [ ] Manual verification completed
|
||||||
|
|
||||||
|
## Related
|
||||||
|
Issue/Task:
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
Any deployment, migration, or follow-up notes.
|
||||||
19
.gitignore
vendored
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
# production
|
# production
|
||||||
/build
|
/build
|
||||||
.github
|
.github/agents
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
.DS_Store
|
.DS_Store
|
||||||
@ -44,3 +44,20 @@ next-env.d.ts
|
|||||||
|
|
||||||
# local documentation
|
# local documentation
|
||||||
docs.txt
|
docs.txt
|
||||||
|
ROADMAP.local.md
|
||||||
|
|
||||||
|
# heap snapshots & analysis artifacts
|
||||||
|
*.heapsnapshot
|
||||||
|
scripts/heap-analysis/output/
|
||||||
|
scripts/heap-analysis/__pycache__/
|
||||||
|
|
||||||
|
# internal planning docs (not for public release)
|
||||||
|
docs/internal/
|
||||||
|
|
||||||
|
# heap analysis tooling & output
|
||||||
|
scripts/
|
||||||
|
scripts/heap-analysis/
|
||||||
|
|
||||||
|
# editor settings
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
65
CLAUDE.md
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# CLAUDE.md
|
||||||
|
|
||||||
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||||
|
|
||||||
|
## Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev # Start dev server (Turbopack)
|
||||||
|
npm run build # Production build
|
||||||
|
npm run start # Start production server
|
||||||
|
npm run lint # ESLint (flat config, ESLint 9)
|
||||||
|
```
|
||||||
|
|
||||||
|
No test framework is configured.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
Aeris is a **Next.js 16 App Router** application for real-time 3D flight tracking, built with React 19, TypeScript (strict), and Tailwind CSS v4. Deployed on Vercel.
|
||||||
|
|
||||||
|
### Rendering stack
|
||||||
|
|
||||||
|
- **MapLibre GL JS** renders the base map (CARTO Dark Matter tiles)
|
||||||
|
- **Deck.gl 9** overlays WebGL layers on top: IconLayer (aircraft), PathLayer (trails), ScenegraphLayer (14 3D GLB models served from Cloudinary CDN)
|
||||||
|
- Altitude drives both z-displacement (`Math.max(altitude * 5, 200)` meters) and color (11-stop RGB gradient)
|
||||||
|
- **Motion** (Framer Motion v12) handles UI animations with spring physics
|
||||||
|
|
||||||
|
### Data flow
|
||||||
|
|
||||||
|
Flight data uses a **3-tier fallback with circuit breaker**:
|
||||||
|
1. **adsb.lol** — proxied through `/api/flights` (primary)
|
||||||
|
2. **OpenSky Network** — direct browser fetch (CORS-enabled)
|
||||||
|
3. **Airplanes.live** — override only
|
||||||
|
|
||||||
|
Polling is adaptive: 10s normally, backs off to 5 min on rate limits. Pauses when tab is hidden (Page Visibility API).
|
||||||
|
|
||||||
|
### Key source layout
|
||||||
|
|
||||||
|
- `src/app/api/` — 8 proxy routes (flights, ATC audio, weather/METAR, aircraft photos, airspace tiles, radar tiles). All external API calls go through these proxies for CORS and SSRF protection.
|
||||||
|
- `src/components/flight-tracker.tsx` — Main orchestrator: manages state, camera modes, layers, and UI composition.
|
||||||
|
- `src/components/map/` — MapLibre context, Deck.gl layer builders, camera controllers (orbit/FPV/globe), animation helpers with Catmull-Rom spline smoothing.
|
||||||
|
- `src/components/ui/` — UI panels (control panel, flight card, ATC panel, FPV HUD, etc.). Uses Radix UI primitives, cmdk for search, Sonner for toasts.
|
||||||
|
- `src/hooks/` — Data fetching hooks (`use-flights`, `use-flight-track`, `use-trail-history`), settings context with localStorage persistence, ATC stream management.
|
||||||
|
- `src/lib/` — API clients, trail processing (cleanup, stitching, spline interpolation), large static datasets (airports 1.3MB, ATC feeds 200KB, airline logos), GPU memory monitoring.
|
||||||
|
|
||||||
|
### State management
|
||||||
|
|
||||||
|
React hooks + context only. Settings persist to localStorage via `use-settings.tsx`. URL params enable deep linking (`?city=IATA`, `?fpv=ICAO24`). SSR hydration uses `useSyncExternalStore`.
|
||||||
|
|
||||||
|
### Trail system
|
||||||
|
|
||||||
|
Per-aircraft trail history with 100-point accumulation buffer, Catmull-Rom spline smoothing, and grid-snapped deduplication. Configurable distance (12–100 points) and thickness (0.5–8 px).
|
||||||
|
|
||||||
|
## Style conventions
|
||||||
|
|
||||||
|
- Conventional commits: `feat:`, `fix:`, `refactor:`, etc.
|
||||||
|
- Path alias: `@/*` maps to `./src/*`
|
||||||
|
- OKLCH color system via CSS custom properties in `globals.css`
|
||||||
|
- Dark-first design with `next-themes`
|
||||||
|
- No server-side secrets required; env vars are optional (`NEXT_PUBLIC_GA_ID`)
|
||||||
|
|
||||||
|
## Build notes
|
||||||
|
|
||||||
|
- `next.config.ts` transpiles Deck.gl and Luma.gl packages
|
||||||
|
- CSP headers and aggressive caching on `/models` (immutable, 1-year max-age)
|
||||||
|
- License: AGPL-3.0
|
||||||
21
CODE_OF_CONDUCT.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Code of Conduct
|
||||||
|
|
||||||
|
## Our Commitment
|
||||||
|
We are committed to a respectful, inclusive, and constructive environment for everyone participating in this project.
|
||||||
|
|
||||||
|
## Expected Behavior
|
||||||
|
- Be respectful and professional.
|
||||||
|
- Provide constructive feedback.
|
||||||
|
- Focus on technical discussion and project goals.
|
||||||
|
- Assume good intent and communicate clearly.
|
||||||
|
|
||||||
|
## Unacceptable Behavior
|
||||||
|
- Harassment, discrimination, or personal attacks.
|
||||||
|
- Threatening, abusive, or disruptive conduct.
|
||||||
|
- Sharing private information without consent.
|
||||||
|
|
||||||
|
## Reporting
|
||||||
|
Report concerns to the maintainers through private repository contact channels. Reports will be reviewed promptly and handled confidentially where possible.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
Maintainers may remove, edit, or reject contributions and interactions that violate this Code of Conduct.
|
||||||
21
CONTRIBUTING.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Contributing
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
1. Create a branch from `main`.
|
||||||
|
2. Make focused, minimal changes.
|
||||||
|
3. Run relevant checks locally.
|
||||||
|
4. Open a pull request with clear context.
|
||||||
|
|
||||||
|
## Pull Request Expectations
|
||||||
|
- Keep PRs scoped to one topic.
|
||||||
|
- Include a short summary of what changed and why.
|
||||||
|
- Reference related issues when applicable.
|
||||||
|
- Update docs when behavior changes.
|
||||||
|
|
||||||
|
## Code Quality
|
||||||
|
- Follow existing project style and conventions.
|
||||||
|
- Avoid unrelated refactors.
|
||||||
|
- Prefer clear, maintainable implementations.
|
||||||
|
|
||||||
|
## Commit Messages
|
||||||
|
Use concise, descriptive commit messages (for example: `feat: add airport search index`).
|
||||||
73
README.md
@ -6,33 +6,28 @@ Aeris renders live air traffic over the world's busiest airspaces on a premium d
|
|||||||
|
|
||||||
[Live Demo](https://aeris.edbn.me)
|
[Live Demo](https://aeris.edbn.me)
|
||||||
|
|
||||||
|
|
||||||
<img width="2559" height="1380" alt="Screenshot 2026-02-15 112222" src="https://github.com/user-attachments/assets/9d1f50ed-be4e-4ef5-95ac-257e9129f8c8" />
|
<img width="2559" height="1380" alt="Screenshot 2026-02-15 112222" src="https://github.com/user-attachments/assets/9d1f50ed-be4e-4ef5-95ac-257e9129f8c8" />
|
||||||
|
|
||||||
|
|
||||||
<img width="2555" height="1387" alt="image" src="https://github.com/user-attachments/assets/a1d2f673-dfdc-4c82-8ee2-7629d91ad94b" />
|
<img width="2555" height="1387" alt="image" src="https://github.com/user-attachments/assets/a1d2f673-dfdc-4c82-8ee2-7629d91ad94b" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Stack
|
## Stack
|
||||||
|
|
||||||
| Layer | Technology |
|
| Layer | Technology |
|
||||||
| --------- | ----------------------------------------------- |
|
| --------- | ---------------------------------------------------------------- |
|
||||||
| Framework | Next.js 16 (App Router, Turbopack) |
|
| Framework | Next.js 16 (App Router, Turbopack) |
|
||||||
| Language | TypeScript |
|
| Language | TypeScript |
|
||||||
| Styling | Tailwind CSS v4 |
|
| Styling | Tailwind CSS v4 |
|
||||||
| Map | MapLibre GL JS |
|
| Map | MapLibre GL JS |
|
||||||
| WebGL | Deck.gl 9 (IconLayer, PathLayer, MapboxOverlay) |
|
| WebGL | Deck.gl 9 (ScenegraphLayer, IconLayer, PathLayer, MapboxOverlay) |
|
||||||
| Animation | Motion (Framer Motion) |
|
| Animation | Motion (Framer Motion) |
|
||||||
| Data | OpenSky Network API |
|
| Data | Airplanes.live / adsb.lol / OpenSky (3-tier fallback) |
|
||||||
| Hosting | Vercel |
|
| Hosting | Vercel |
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm install
|
pnpm install
|
||||||
cp .env.example .env.local
|
cp .env.example .env.local
|
||||||
# Optionally add OpenSky credentials — see .env.example
|
|
||||||
pnpm dev
|
pnpm dev
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -46,12 +41,14 @@ src/
|
|||||||
│ ├── globals.css Tailwind config, theme vars
|
│ ├── globals.css Tailwind config, theme vars
|
||||||
│ ├── layout.tsx Root layout (Inter font)
|
│ ├── layout.tsx Root layout (Inter font)
|
||||||
│ ├── page.tsx Entry — renders <FlightTracker />
|
│ ├── page.tsx Entry — renders <FlightTracker />
|
||||||
│ └── api/flights/route.ts OpenSky proxy with rate limiting + auth
|
│ └── api/flights/route.ts adsb.lol reverse proxy (CORS workaround + rate limit)
|
||||||
├── components/
|
├── components/
|
||||||
│ ├── flight-tracker.tsx Orchestrator — state, camera, layers, UI
|
│ ├── flight-tracker.tsx Orchestrator — state, camera, layers, UI
|
||||||
│ ├── map/
|
│ ├── map/
|
||||||
│ │ ├── map.tsx MapLibre GL wrapper with React context
|
│ │ ├── map.tsx MapLibre GL wrapper with React context
|
||||||
│ │ └── flight-layers.tsx Deck.gl overlay — icons, trails, shadows, animation
|
│ │ ├── flight-layers.tsx Deck.gl overlay — icons, trails, shadows, animation
|
||||||
|
│ │ ├── aircraft-model-mapping.ts ADS-B category → 3D model key + bucketing
|
||||||
|
│ │ └── aircraft-model-layers.ts Builds per-model ScenegraphLayers
|
||||||
│ └── ui/
|
│ └── ui/
|
||||||
│ ├── altitude-legend.tsx
|
│ ├── altitude-legend.tsx
|
||||||
│ ├── control-panel.tsx Tabbed dialog — search, map style, settings
|
│ ├── control-panel.tsx Tabbed dialog — search, map style, settings
|
||||||
@ -65,9 +62,13 @@ src/
|
|||||||
│ └── use-trail-history.ts Trail accumulation + Catmull-Rom smoothing
|
│ └── use-trail-history.ts Trail accumulation + Catmull-Rom smoothing
|
||||||
└── lib/
|
└── lib/
|
||||||
├── cities.ts Curated aviation hub presets
|
├── cities.ts Curated aviation hub presets
|
||||||
|
├── flight-api.ts Barrel re-export for the 3-tier flight client
|
||||||
|
├── flight-api-client.ts airplanes.live → adsb.lol → OpenSky fallback chain
|
||||||
|
├── flight-api-parsing.ts readsb JSON → FlightState normalization
|
||||||
|
├── flight-api-types.ts Shared types for ADS-B providers
|
||||||
├── flight-utils.ts Altitude→color, unit conversions
|
├── flight-utils.ts Altitude→color, unit conversions
|
||||||
├── map-styles.ts Map style definitions
|
├── map-styles.ts Map style definitions
|
||||||
├── opensky.ts OpenSky API client + types
|
├── opensky.ts OpenSky API client + types (Tier 3 fallback)
|
||||||
└── utils.ts cn() utility
|
└── utils.ts cn() utility
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -75,6 +76,30 @@ src/
|
|||||||
|
|
||||||
- **Dark-first**: CARTO Dark Matter base map, theme-aware UI
|
- **Dark-first**: CARTO Dark Matter base map, theme-aware UI
|
||||||
- **3D depth**: 55° pitch, altitude-based z-displacement via Deck.gl
|
- **3D depth**: 55° pitch, altitude-based z-displacement via Deck.gl
|
||||||
|
|
||||||
|
## Aircraft Models
|
||||||
|
|
||||||
|
Aeris renders 14 distinct aircraft silhouettes based on ADS-B emitter category and ICAO type code:
|
||||||
|
|
||||||
|
| Model Key | Represents | Assignment |
|
||||||
|
| --------------- | ------------------------------- | ---------------------------------------------- |
|
||||||
|
| `narrowbody` | A320, B737 family | Category 3 (Small), 4 (Large), 5 (High vortex) |
|
||||||
|
| `widebody-2eng` | A330, A350, B777, B787 | Category 6 (Heavy) |
|
||||||
|
| `widebody-4eng` | A380, B747, A340 | — |
|
||||||
|
| `a380` | Airbus A380 | Type codes A38x |
|
||||||
|
| `b737` | Boeing 737 family | Type codes B73x, B3xM |
|
||||||
|
| `regional-jet` | CRJ, E-Jets, Fokker | — |
|
||||||
|
| `light-prop` | Cessna, Piper, Cirrus | Category 2 (Light), 12 (Ultralight) |
|
||||||
|
| `turboprop` | ATR, Dash-8, Saab | — |
|
||||||
|
| `helicopter` | All rotorcraft | Category 8 (Rotorcraft) |
|
||||||
|
| `bizjet` | Gulfstream, Citation, Learjet | — |
|
||||||
|
| `glider` | Sailplanes | Category 9 (Glider) |
|
||||||
|
| `fighter` | Military fast-movers | Category 7 (High-perf) |
|
||||||
|
| `drone` | UAVs | Category 14 (UAV) |
|
||||||
|
| `generic` | Fallback for unknown categories | Category 0, 1, default |
|
||||||
|
|
||||||
|
Models are optimised GLB files (no Draco compression — avoids external WASM decoder dependency) served from Cloudinary CDN (local backups in `public/models/aircraft/`). A second-tier mapping from ICAO type codes (A320, B738, etc.) refines the assignment when type data is available via the readsb feed.
|
||||||
|
|
||||||
- **Smooth animation**: Catmull-Rom spline trails, per-frame interpolation between polls
|
- **Smooth animation**: Catmull-Rom spline trails, per-frame interpolation between polls
|
||||||
- **Glassmorphism**: `backdrop-blur-2xl`, `bg-black/60`, `border-white/[0.08]`
|
- **Glassmorphism**: `backdrop-blur-2xl`, `bg-black/60`, `border-white/[0.08]`
|
||||||
- **Spring physics**: All UI transitions use spring easing
|
- **Spring physics**: All UI transitions use spring easing
|
||||||
@ -84,15 +109,11 @@ src/
|
|||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
| Variable | Required | Description |
|
| Variable | Required | Description |
|
||||||
| ----------------------- | -------- | ------------------------------- |
|
| ------------------- | -------- | ------------------------------- |
|
||||||
| `OPENSKY_CLIENT_ID` | No | OAuth2 client ID (recommended) |
|
| `NEXT_PUBLIC_GA_ID` | No | Google Analytics measurement ID |
|
||||||
| `OPENSKY_CLIENT_SECRET` | No | OAuth2 client secret |
|
|
||||||
| `OPENSKY_USERNAME` | No | Basic auth username (legacy) |
|
|
||||||
| `OPENSKY_PASSWORD` | No | Basic auth password (legacy) |
|
|
||||||
| `NEXT_PUBLIC_GA_ID` | No | Google Analytics measurement ID |
|
|
||||||
|
|
||||||
Without credentials, anonymous access is used (~10 requests/minute).
|
No API keys are needed. Flight data comes from public ADS-B APIs with a built-in 3-tier fallback chain (airplanes.live → adsb.lol → OpenSky).
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
92
docs/3D-MODELS.md
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
# 3D Aircraft Models
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Aeris uses 14 distinct 3D aircraft silhouettes to represent different aircraft types on the globe. Models are assigned based on ICAO type code (when available) or ADS-B emitter category.
|
||||||
|
|
||||||
|
Two iconic aircraft types — the **Airbus A380** and **Boeing 737** — have dedicated models for visual distinction. All other aircraft are mapped to generic silhouette categories.
|
||||||
|
|
||||||
|
## Model Inventory
|
||||||
|
|
||||||
|
| File | Size (KB) | Description | Source |
|
||||||
|
| ------------------- | --------: | ------------------------------------------ | -------------- |
|
||||||
|
| `b737.glb` | 156.1 | Boeing 737 family (incl. MAX) | fr24-3d-models |
|
||||||
|
| `bizjet.glb` | 452.8 | Business jets (Gulfstream, Citation, etc.) | FlightAirMap |
|
||||||
|
| `drone.glb` | 131.0 | Unmanned aerial vehicles | FlightAirMap |
|
||||||
|
| `fighter.glb` | 58.2 | Military high-performance aircraft | FlightAirMap |
|
||||||
|
| `generic.glb` | 401.8 | Default fallback (A320 silhouette) | FlightAirMap |
|
||||||
|
| `glider.glb` | 68.1 | Gliders and sailplanes | FlightAirMap |
|
||||||
|
| `helicopter.glb` | 270.8 | Rotorcraft | FlightAirMap |
|
||||||
|
| `light-prop.glb` | 131.0 | Light GA props (Cessna, Piper, etc.) | FlightAirMap |
|
||||||
|
| `narrowbody.glb` | 401.8 | Narrow-body jets (A320, other non-737) | FlightAirMap |
|
||||||
|
| `regional-jet.glb` | 127.0 | Regional jets (CRJ, Embraer E-Jets) | FlightAirMap |
|
||||||
|
| `turboprop.glb` | 86.4 | Turboprops (ATR, Dash-8) | FlightAirMap |
|
||||||
|
| `widebody-2eng.glb` | 149.3 | Wide-body twin-engine (777, 787, A330) | FlightAirMap |
|
||||||
|
| `widebody-4eng.glb` | 241.8 | Wide-body four-engine (A340, A380) | FlightAirMap |
|
||||||
|
|
||||||
|
### Totals
|
||||||
|
|
||||||
|
| Metric | Value |
|
||||||
|
| --------------------------------- | -------------------: |
|
||||||
|
| **Aircraft models** | 13 files |
|
||||||
|
| **Aircraft total** | 2,676.1 KB (2.61 MB) |
|
||||||
|
| **Legacy model** (`airplane.glb`) | 1,295.2 KB (1.26 MB) |
|
||||||
|
| **All GLB files** | 3,971.3 KB (3.88 MB) |
|
||||||
|
|
||||||
|
## Optimization Pipeline
|
||||||
|
|
||||||
|
All models are optimized for web delivery using `@gltf-transform/cli`:
|
||||||
|
|
||||||
|
1. **Texture stripping** — Materials set to neutral unlit gray
|
||||||
|
2. **Mesh simplification** — Triangle count reduced to ~30% of original
|
||||||
|
3. **B737 format conversion** — Converted from glTF 1.0 → 2.0 via `gltf-pipeline`
|
||||||
|
|
||||||
|
> Note: Draco compression is **not** used for these models, to avoid
|
||||||
|
> introducing an external WASM decoder dependency.
|
||||||
|
> See `public/models/aircraft/NOTICE.md` for details.
|
||||||
|
|
||||||
|
## Model Assignment
|
||||||
|
|
||||||
|
### Priority: TypeCode → Category
|
||||||
|
|
||||||
|
When an aircraft's ICAO type code is available (from readsb providers), it takes priority over the generic ADS-B category mapping.
|
||||||
|
|
||||||
|
**Dedicated model types:**
|
||||||
|
|
||||||
|
| Aircraft Type | TypeCode Pattern | Model Key |
|
||||||
|
| ---------------- | --------------------- | --------- |
|
||||||
|
| Airbus A380 | `A38x` | `a380` |
|
||||||
|
| Boeing 737 (all) | `B73x`, `B37M`–`B39M` | `b737` |
|
||||||
|
|
||||||
|
**Category-based fallback (DO-260B):**
|
||||||
|
|
||||||
|
| ADS-B Category | Weight Class | Model Key |
|
||||||
|
| -------------- | ---------------------- | --------------- |
|
||||||
|
| 2 | Light (<15,500 lbs) | `light-prop` |
|
||||||
|
| 3 | Small (15,500–75,000) | `narrowbody` |
|
||||||
|
| 4 | Large (75,000–300,000) | `narrowbody` |
|
||||||
|
| 5 | High vortex (B757) | `narrowbody` |
|
||||||
|
| 6 | Heavy (>300,000 lbs) | `widebody-2eng` |
|
||||||
|
| 7 | High performance | `fighter` |
|
||||||
|
| 8 | Rotorcraft | `helicopter` |
|
||||||
|
| 9 | Glider/sailplane | `glider` |
|
||||||
|
| 12 | Ultralight | `light-prop` |
|
||||||
|
| 14 | UAV | `drone` |
|
||||||
|
| Other | Unknown | `generic` |
|
||||||
|
|
||||||
|
## Performance
|
||||||
|
|
||||||
|
- Models are **lazy-loaded**: only fetched when an aircraft of that type first appears in data
|
||||||
|
- The 6 most common model types are **prefetched** via `<link rel="prefetch">` on page load
|
||||||
|
- Empty ScenegraphLayers are kept alive with stable empty arrays to avoid shader recompilation
|
||||||
|
- deck.gl caches models by URL, so the `a380` key (which maps to `widebody-4eng.glb`) shares the cache entry
|
||||||
|
|
||||||
|
## Licensing
|
||||||
|
|
||||||
|
All models are licensed under **GPL v2**, compatible with the project's AGPL v3 license.
|
||||||
|
|
||||||
|
- **FlightAirMap-3dmodels**: https://github.com/Ysurac/FlightAirMap-3dmodels
|
||||||
|
- **fr24-3d-models**: https://github.com/Flightradar24/fr24-3d-models
|
||||||
|
- Original sources: [FlightGear FGMEMBERS](https://github.com/FGMEMBERS)
|
||||||
|
|
||||||
|
See [public/models/aircraft/NOTICE.md](../public/models/aircraft/NOTICE.md) for full attribution.
|
||||||
@ -1,5 +1,29 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
|
|
||||||
|
const isDev = process.env.NODE_ENV === "development";
|
||||||
|
|
||||||
|
// Content Security Policy — allows only the external resources Aeris actually uses.
|
||||||
|
// https://nextjs.org/docs/app/guides/content-security-policy
|
||||||
|
//
|
||||||
|
// NOTE: planespotters.net, adsbdb.com, airport-data.com, and jetapi.dev are
|
||||||
|
// server-side only (accessed via /api/aircraft-photos proxy route). CSP does
|
||||||
|
// not apply to server-side fetches, so they are not listed in connect-src.
|
||||||
|
const cspHeader = `
|
||||||
|
default-src 'self';
|
||||||
|
script-src 'self' 'unsafe-inline' https://www.googletagmanager.com${isDev ? " 'unsafe-eval'" : ""};
|
||||||
|
style-src 'self' 'unsafe-inline';
|
||||||
|
img-src 'self' blob: data: https: ;
|
||||||
|
font-src 'self';
|
||||||
|
connect-src 'self' data: https://opensky-network.org https://*.basemaps.cartocdn.com https://basemaps.cartocdn.com https://server.arcgisonline.com https://s3.amazonaws.com https://tile.opentopomap.org https://www.google-analytics.com https://www.googletagmanager.com https://api.github.com https://api.airplanes.live https://api.adsb.lol https://res.cloudinary.com https://api.rainviewer.com;
|
||||||
|
worker-src 'self' blob:;
|
||||||
|
child-src blob:;
|
||||||
|
object-src 'none';
|
||||||
|
base-uri 'self';
|
||||||
|
form-action 'self';
|
||||||
|
frame-ancestors 'none';
|
||||||
|
upgrade-insecure-requests;
|
||||||
|
`;
|
||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
transpilePackages: [
|
transpilePackages: [
|
||||||
"@deck.gl/core",
|
"@deck.gl/core",
|
||||||
@ -25,9 +49,23 @@ const nextConfig: NextConfig = {
|
|||||||
{
|
{
|
||||||
source: "/(.*)",
|
source: "/(.*)",
|
||||||
headers: [
|
headers: [
|
||||||
|
{
|
||||||
|
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-Content-Type-Options", value: "nosniff" },
|
||||||
{ key: "X-Frame-Options", value: "DENY" },
|
{ key: "X-Frame-Options", value: "DENY" },
|
||||||
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
|
{ 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=()",
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
8759
package-lock.json
generated
Normal file
18
package.json
@ -12,11 +12,11 @@
|
|||||||
"lint": "eslint"
|
"lint": "eslint"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@deck.gl/core": "^9.2.7",
|
"@deck.gl/core": "^9.2.11",
|
||||||
"@deck.gl/geo-layers": "^9.2.7",
|
"@deck.gl/geo-layers": "^9.2.7",
|
||||||
"@deck.gl/layers": "^9.2.7",
|
"@deck.gl/layers": "^9.2.11",
|
||||||
"@deck.gl/mapbox": "^9.2.7",
|
"@deck.gl/mapbox": "^9.2.11",
|
||||||
"@deck.gl/mesh-layers": "^9.2.7",
|
"@deck.gl/mesh-layers": "^9.2.11",
|
||||||
"@deck.gl/react": "^9.2.7",
|
"@deck.gl/react": "^9.2.7",
|
||||||
"@loaders.gl/core": "^4.3.4",
|
"@loaders.gl/core": "^4.3.4",
|
||||||
"@loaders.gl/gltf": "^4.3.4",
|
"@loaders.gl/gltf": "^4.3.4",
|
||||||
@ -24,13 +24,15 @@
|
|||||||
"@luma.gl/webgl": "^9.2.6",
|
"@luma.gl/webgl": "^9.2.6",
|
||||||
"@radix-ui/react-slider": "^1.3.6",
|
"@radix-ui/react-slider": "^1.3.6",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
"cmdk": "^1.1.1",
|
||||||
"lucide-react": "^0.564.0",
|
"lucide-react": "^0.564.0",
|
||||||
"maplibre-gl": "^5.18.0",
|
"maplibre-gl": "^5.18.0",
|
||||||
"motion": "^12.34.0",
|
"motion": "^12.34.0",
|
||||||
"next": "16.1.6",
|
"next": "16.2.1",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"react": "19.2.3",
|
"react": "19.2.4",
|
||||||
"react-dom": "19.2.3",
|
"react-dom": "19.2.4",
|
||||||
|
"sonner": "^2.0.7",
|
||||||
"tailwind-merge": "^3.4.0"
|
"tailwind-merge": "^3.4.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@ -39,7 +41,7 @@
|
|||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"eslint": "^9",
|
"eslint": "^9",
|
||||||
"eslint-config-next": "16.1.6",
|
"eslint-config-next": "16.2.0",
|
||||||
"tailwindcss": "^4",
|
"tailwindcss": "^4",
|
||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
}
|
}
|
||||||
|
|||||||
720
pnpm-lock.yaml
generated
BIN
public/aeris-hero.png
Normal file
|
After Width: | Height: | Size: 396 KiB |
BIN
public/airline-logos/aegean-airlines.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
public/airline-logos/aer-lingus.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
1
public/airline-logos/aeroflot.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="#02458D" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Aeroflot</title><path d="M9.066 12.725c-.056-.135-.097-.272-.143-.406l-6.675.406 1.35.693zm.909 1.247c-.057-.042-.115-.1-.17-.15a1.822 1.822 0 0 1-.287-.318l-3.333.67 1.419.509zm2.64-.286c.16-.025.4-.122.588-.268l-.968-2.032 1.005-.51-.848-.782c-.602.292-1.206.58-1.809.868l.43 1.025.694-.33zm1.65-4.241c.387.5.655 1.081.782 1.7h-.61a3.884 3.884 0 0 0-.172-.57c-.41-1.142-1.25-1.956-2.216-2.633-.127-.078-.241-.164-.37-.238.129.044.243.086.37.136.88.372 1.662.885 2.216 1.605m.185 6.517c-.225.114-.455.22-.682.33l-.565-1.193c-.37.139-.76.215-1.154.226-.424.02-.847-.04-1.249-.176l-.483 1.143c-.157.014-.374 0-.512-.106a.378.378 0 0 1-.169-.224c.204-.356.389-.723.579-1.087-.127-.088-.24-.152-.355-.27l.344-.437c.582.38 1.22.585 1.845.585.627.022 1.25-.192 1.832-.628.19.055.385.119.541.18-.058.046-.1.087-.157.136-.114.12-.213.242-.398.346.188.395.387.784.583 1.175zm7.785-3.431L24 11.343h-9.55c0 .422-.06.784-.185 1.1-.369 1.005-1.291 1.487-2.216 1.469-.908-.027-1.834-.524-2.244-1.441a2.745 2.745 0 0 1-.229-1.128H0l1.75 1.188 7.316-.404c.138.553.397 1.037.74 1.395a3.065 3.065 0 0 0 2.243 1.01 2.79 2.79 0 0 0 2.216-.992c.312-.362.554-.826.694-1.385zm-.48.194l-1.352.663L15 12.725a9.5 9.5 0 0 0 .129-.406zm-3.907 1.462l-1.48.52a357.77 357.77 0 0 1-2.286-.735c.069-.06.125-.117.183-.196.085-.074.157-.176.242-.254zm.711-.09l1.177-.575-4.86-.614c-.043.164-.171.298-.256.432zm-13.116 0l-1.179-.542 4.885-.635c.09.152.171.286.27.42Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
BIN
public/airline-logos/aerola-neas-argentinas.png
Normal file
|
After Width: | Height: | Size: 683 B |
BIN
public/airline-logos/aeroma-xico.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
public/airline-logos/air-algerie.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
public/airline-logos/air-arabia.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
public/airline-logos/air-astana.png
Normal file
|
After Width: | Height: | Size: 768 B |
BIN
public/airline-logos/air-baltic.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
public/airline-logos/air-berlin.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
public/airline-logos/air-busan.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
public/airline-logos/air-canada-jazz.png
Normal file
|
After Width: | Height: | Size: 717 B |
1
public/airline-logos/air-canada.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="#F01428" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Air Canada</title><path d="M12.394 16.958c0-.789.338-.902 1.127-.451a54.235 54.235 0 0 0 2.704 1.465c0-.45.451-.789 1.24-.564.789.226 1.577.338 1.577.338s-.45-1.014-.676-1.464c-.338-.789 0-1.24.338-1.352 0 0-.45-.338-.789-.564-.676-.45-.563-1.014.113-1.24.902-.45 2.141-.9 2.141-.9-.338-.226-.789-.79-.338-1.578.45-.676 1.24-1.69 1.24-1.69H18.93c-.79 0-1.015-.676-1.015-1.127 0 0-1.239.901-2.14 1.465-.79.563-1.465 0-1.352-.902a37 37 0 0 0 .338-2.93c-.451.451-1.24.339-1.69-.337-.564-1.127-1.127-2.48-1.127-2.48S11.38 4 10.817 5.128c-.338.676-1.127.788-1.578.45a37 37 0 0 0 .338 2.93c.113.789-.563 1.352-1.352.789-.901-.564-2.253-1.465-2.253-1.465 0 .45-.226 1.014-1.014 1.127H2.817s.789 1.014 1.24 1.69c.45.676 0 1.352-.339 1.577 0 0 1.127.564 2.141.902.676.338.902.788.113 1.24-.226.225-.789.563-.789.563.45.112.789.563.45 1.352-.225.45-.675 1.464-.675 1.464s.788-.225 1.577-.338c.789-.225 1.127.226 1.24.564 0 0 1.352-.789 2.704-1.465.676-.45 1.127-.225 1.127.45v1.916c0 1.127-.226 2.254-.564 2.93-5.07-.564-9.352-4.62-9.352-10.028 0-5.521 4.62-10.029 10.366-10.029 5.747 0 10.367 4.508 10.367 10.029 0 5.183-4.057 9.464-9.24 10.028v1.352C19.268 22.592 24 17.746 24 11.775 24 5.352 18.592.282 11.944.282 5.408.282 0 5.352 0 11.662c0 5.521 4.169 10.14 9.69 11.155.902.225 1.465.338 2.028.901.564-1.126.676-3.38.676-4.62Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
1
public/airline-logos/air-china.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="#E30E17" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Air China</title><path d="M6.75 23.377c3.431.96 7.361-1.449 7.361-5.442v-4.713c0-1.377 1.147-3.19 3.212-3.19 2.17 0 3.201 1.949 3.201 3.19 0 .792-.313 2.377-1.804 2.377-1.188 0-1.95-1.21-1.574-2.2-.083.333.093.657.449.657.343 0 .532-.324.468-.73 0-.083-.104-.834-.939-.834-.698 0-.927.636-.927.948v4.193c0 4.483-4.88 7.798-9.447 5.744M3.508 19.99s2.303 2.336 5.338.573c2.012-1.167 2.075-3.598 2.075-3.598v-5.431s-.084-2.722 2.366-4.672c1.711-1.345 3.296-1.252 4.39-1.387 2.806-.344 4.057-2.116 4.057-2.116.031.302-.272 3.555-3.785 4.483-.72.188-4.578-.187-4.578 4.275v5.38c0 1.126-.27 3.118-2.377 4.526-2.169 1.439-5.683 1.21-7.486-2.033M1.047 8.759H3.85c0-.5.428-1.471 1.523-1.471.427 0 .5.095 1.052-.02.72-.24 1.043-.657 1.19-.99 0 0 .28 1.187-.845 1.813-.637.345-1.616.074-1.616.074s-.792-.115-.897.593c.449 0 1.147.449 1.147 1.22v6.528c0 .469.375.96.949.96a.95.95 0 0 0 .949-.96v-4.578c0-6.757 5.255-9.56 8.31-9.79 2.533-.188 4.244.04 7.34-2.138 0 0-.97 3.796-5.358 4.703-.804.166-3.224-.115-5.497 2.252-1.803 1.877-1.99 3.608-1.99 5.891v4.035c0 1.762-1.419 3.545-3.587 3.545-2.096 0-3.566-1.668-3.566-3.545v-6.85c0-.563-.406-1.074-1.054-1.074h-.854Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
BIN
public/airline-logos/air-corsica.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
public/airline-logos/air-do.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
public/airline-logos/air-dolomiti.png
Normal file
|
After Width: | Height: | Size: 953 B |
BIN
public/airline-logos/air-europa.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
1
public/airline-logos/air-france.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="#002157" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Air France</title><path d="M13.776 3.9L5.184 16.332C4.051 17.969 2.208 19.548 0 19.721v.379h9.552c2.544 0 4.397-1.656 5.616-3.48L24 3.9Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 238 B |
BIN
public/airline-logos/air-greenland.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
public/airline-logos/air-india-express.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
1
public/airline-logos/air-india.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="#DA0E29" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Air India</title><path d="M8.483.001C6.247.043 4.102 1.018 2.092 2.898c.141-.065-.545.44-1.637 1.676.013.006-.009.017-.013.025 0 0 .014.037.14-.064.75-.61 3.198-2.893 9.86.101a276.52 276.52 0 0 0 6.42 2.78s1.027 3.236 2.207 6.637c2.398 6.89-.087 9.135-.76 9.82-.102.114-.064.127-.064.127a16.746 16.746 0 0 0 2.385-2.08c1.624-1.637 2.588-3.428 2.855-5.344.254-1.878-.203-3.5-.584-4.566-.266-.75-.481-1.346-.672-1.88-.862-2.423-1.028-2.867-1.625-5.29l-.203-.8c-.023-.003.009-.016.014-.025l-.787-.254c-2.386-.774-2.804-.964-5.165-2.017-.52-.229-1.103-.496-1.826-.813-.85-.368-2.146-.875-3.707-.926a8.027 8.027 0 0 0-.447-.004Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 725 B |
BIN
public/airline-logos/air-koryo.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
public/airline-logos/air-madagascar.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
public/airline-logos/air-malta.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
public/airline-logos/air-mauritius.png
Normal file
|
After Width: | Height: | Size: 872 B |
BIN
public/airline-logos/air-new-zealand.png
Normal file
|
After Width: | Height: | Size: 606 B |
BIN
public/airline-logos/air-niugini.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
public/airline-logos/air-nostrum.png
Normal file
|
After Width: | Height: | Size: 717 B |
BIN
public/airline-logos/air-peace.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
public/airline-logos/air-senegal.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
1
public/airline-logos/air-serbia.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="#0E203F" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Air Serbia</title><path d="m16.667 3.754-1.148.002-.455.169s-.25.062-.416.482l-.343 1.079s-.094.358-.118.903c-.018.546-.008.019-.008.019s-.026.81-.119 1.055l-.184.643c-.27.634-.546.945-.551.955l-1.032 1.193v.005l-.292.327-.287-.327.006-.006-.639-.725-.086-.104h-.004l-.32-.362c-.003-.01-.294-.343-.566-1.01l-.172-.588c-.093-.245-.12-1.055-.12-1.055s.011.527-.01-.019a4.555 4.555 0 0 0-.113-.903l-.346-1.079c-.169-.42-.415-.483-.415-.483l-.453-.168-1.15-.002-.184.268c-.205.193-.258.116-.531.158-.217.03-.294.043-.473.181-.231.188-.264.434-.264.434v.465l.014.319.262-.325c.443-.018 1.06.252 1.06.252l-.074.182c-.064.144-.063.268-.063.268s-.032.526-.095.84c-.018.092-.03.245-.085.398-.091.268-.564.793-.67.913l-.594.638c-.454-.366-1.24-.853-2.244-.891C2.312 7.81 1.275 8.27.3 9.223L0 9.521l.225.352c.034.055.833 1.292 2.274 1.57.93.181 1.946-.102 2.908-.791l-.703-.793c-.713.515-1.36.686-1.998.565-.598-.114-1.057-.487-1.325-.773.649-.526 1.303-.786 1.95-.76 1.137.041 1.942.932 1.947.94l1.685 1.948.69-.797-1.292-1.49 1.512-1.881.614-.768c.144.761.834 2.071 1.128 2.527l-1.677 1.948-.67.78-.008.01-.006.01-.713.826c-.373.394-1.675 1.679-3.203 2.497 0 0 .48.329 1.107.323.377-.008.813-.14 1.225-.533.17-.158.42-.385.667-.615 0 0-.114.274.155.781.212.386.573.62 1.073.636.777.03 1.333-.375 1.718-.845l-.554-.61s-.5.714-1.114.278c-.225-.212-.206-.57-.206-.57s-.01-.12.109-.373c.417-.705 1.56-2.19 2.236-3.058l.521-.66.747.858.002-.004.291.338-.002.006.02.018-1.303 1.61.59.667L12 12.182v.005l.004-.005 1.685 1.871.7.787.247.26.175.192c.382.42.914.767 1.627.741.5-.017.864-.25 1.075-.636.271-.506.156-.781.156-.781.247.23.493.457.665.615 1.107 1.05 2.331.21 2.331.21-1.523-.818-2.825-2.103-3.195-2.496l-.408-.47-.852.95c.41.565.394.861.394.861s.011.36-.212.571c-.607.441-1.149-.318-1.149-.318l-1.692-2.052-.005-.012-.873-1.07.017-.017.644-.742h-.004l.39-.45.173.214 1.105 1.492.778-.919-1.267-1.475-.001.003-.122-.14c.296-.457.983-1.767 1.126-2.528l.617.768 1.51 1.881-.31.358-1.268 1.468-1.1 1.26-.325.384.688.794.54-.632v.003l.064-.068.82-.947.48-.556 1.495-1.726c.008-.007.805-.898 1.947-.939.652-.026 1.302.234 1.949.76-.269.286-.724.659-1.322.773-.64.12-1.294-.056-2.008-.566l-.686.788c.962.69 1.966.978 2.902.798 1.435-.28 2.233-1.516 2.269-1.57L24 9.52l-.297-.298c-.978-.952-2.017-1.413-3.088-1.368l.001-.001c-.851.032-1.542.384-2.012.716l-.052.037c-.004.001-.012.012-.013.012-.062.046-.124.085-.173.126l-.743-.8c-.176-.213-.453-.557-.521-.75-.057-.154-.071-.307-.084-.399a8.035 8.035 0 0 1-.099-.84s0-.124-.058-.268l-.073-.182s.618-.27 1.054-.252l.27.325.004-.319v-.465s-.028-.247-.265-.434c-.178-.138-.256-.15-.47-.18-.275-.042-.32.034-.525-.159zm-7.648 8.8-.633.84.718.836.84.992 1.074 1.239.692-.794-1.37-1.573-.684-.798zm4.374 1.841-.966 1.12-1.115 1.284c-1.118 1.04-1.204 1.43-1.204 1.43-.467 1.174.15 2.017.15 2.017.089-.733.713-1.444.935-1.72l.433-.496v-.002l1.534-1.775.91-1.046zm-.41 2.709-.706.83.08.094-.002.002.43.496c.225.276.845.987.937 1.72 0 0 .613-.843.15-2.018 0 0-.07-.313-.888-1.124z"/></svg>
|
||||||
|
After Width: | Height: | Size: 3.0 KiB |
BIN
public/airline-logos/air-seychelles.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
public/airline-logos/air-tanzania.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
1
public/airline-logos/air-transat.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="#172B54" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Air Transat</title><path d="M17.611 0c-2.931.916-5.68 3.434-8.474 6.137C5.564 6.32 1.672 7.74 1.26 7.969c4.122 2.152 5.129 3.115 5.129 3.115s-1.374 3.938-1.649 6.457c.916-2.244 2.702-5.312 3.801-6.777-1.511-1.237-4.35-2.565-4.35-2.565s2.244-.962 6.733-1.191c0 0 1.878-3.619 6.687-7.008zm-2.244 3.344c-.412.87-1.146 2.793-1.283 4.213 3.16.229 5.312.963 5.312.963s-3.205 1.19-4.992 2.609c.32.779 1.055 3.07 1.467 4.855-.687-.64-2.748-2.336-4.26-3.252C9.596 13.511 4.1 18.962 1.031 24c1.328-1.374 5.267-5.817 10.58-9.023 1.1.64 6.137 3.939 6.137 3.939s-1.1-5.862-1.512-7.236c1.558-1.054 4.214-2.52 6.733-3.3-3.527-1.419-7.832-1.784-7.832-1.784s-.09-1.1.23-3.252z"/></svg>
|
||||||
|
After Width: | Height: | Size: 761 B |
BIN
public/airline-logos/airasia-x.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
1
public/airline-logos/airasia.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="#FF0000" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>AirAsia</title><path d="M11.54 14.49c-1.278 0-2.264-.998-2.264-2.276 0-1.252.98-2.27 2.264-2.27 1.232 0 2.238 1.018 2.238 2.27 0 1.278-1.005 2.277-2.239 2.277zm3.074-7.854l-.214.998c-.59-1.18-2.348-1.297-3.295-1.297-2.952 0-5.527 2.841-5.527 6.746 0 3.14 1.875 5.111 4.23 5.111 1.316 0 2.432-.304 3.353-1.4l-.24 1.102h3.711l1.692-11.26c-1.238-.001-2.482.01-3.71 0zM12 0c6.63 0 12 5.37 12 12s-5.37 12-12 12S0 18.63 0 12 5.37 0 12 0Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 533 B |
BIN
public/airline-logos/airbridgecargo-airlines.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
public/airline-logos/akasa-air.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
public/airline-logos/alaska-airlines.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
public/airline-logos/alitalia-ita-airways.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
public/airline-logos/alitalia.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
public/airline-logos/all-nippon-airways.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
public/airline-logos/allegiant-air.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
1
public/airline-logos/american-airlines.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="#0078D2" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>American Airlines</title><path d="M0 .244h3.264c1.377 0 1.942.563 2.499 1.116.637.58 2.57 3.196 6.657 8.303H7.997c-1.809 0-2.38-.308-3.08-1.375zm10.424 17.072l-2.427-4.013c-.292-.455-.372-.854-.372-1.318 0-.51.217-.79 1.053-1.233.973-.466 2.933-.67 4.954-.67 3.283 0 4.07 1.055 4.405 2.192 0 0-.464-.185-1.554-.185-3.459 0-6.223 1.68-6.223 4.221 0 .534.164 1.006.164 1.006zm4.936-3.417c-2.547.089-5.032 1.869-4.936 3.416l2.7 4.486c.836 1.344 2.215 1.955 3.932 1.955H24l-8.13-9.852a5.55 5.55 0 0 0-.51-.005Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 608 B |
BIN
public/airline-logos/ameriflight.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
public/airline-logos/amerijet.png
Normal file
|
After Width: | Height: | Size: 717 B |
BIN
public/airline-logos/ana.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
public/airline-logos/ariana-afghan-airlines.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
public/airline-logos/arkia-israeli-airlines.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
public/airline-logos/asiana-airlines.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
public/airline-logos/asl-airlines-belgium.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
public/airline-logos/asl-airlines-france.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
public/airline-logos/atlas-air.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
public/airline-logos/aurigny-air-services.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
public/airline-logos/aurora.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
public/airline-logos/austrian-airlines.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
1
public/airline-logos/avianca.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="#FF0000" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>avianca</title><path d="M3.813 0s-2.326 2.052-2.51 6.367c-.205 4.716 2.324 9.47 10.654 10.076.026.005.055.005.08.008C7.806 11.534 4.955 5.241 3.812 0zm8.224 16.451a30.654 30.654 0 0 0 2.2 2.303H5.282c.12.278.53.472 1.463.527 5.59.332 6.38 4.719 14.381 4.719.702 0 1.14-.042 1.582-.125-3.16-.972-6-2.8-8.47-5.121h2.21c.917 0 1.325.076 1.58.191-.392-1.218-1.631-2.168-5.992-2.494z"/></svg>
|
||||||
|
After Width: | Height: | Size: 480 B |
BIN
public/airline-logos/avion-express.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
public/airline-logos/azerbaijan-airlines.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
public/airline-logos/azul.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
public/airline-logos/bamboo-airways.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
public/airline-logos/bangkok-airways.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
public/airline-logos/batik-air.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
public/airline-logos/beijing-capital-airlines.png
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
public/airline-logos/belavia.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
public/airline-logos/biman-bangladesh-airlines.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
public/airline-logos/binter-canarias.png
Normal file
|
After Width: | Height: | Size: 628 B |
BIN
public/airline-logos/blue-air.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
public/airline-logos/boliviana-de-aviacion.png
Normal file
|
After Width: | Height: | Size: 2.7 KiB |
BIN
public/airline-logos/breeze-airways.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
1
public/airline-logos/british-airways.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg fill="#2E5C99" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>British Airways</title><path d="M23.489 13.252c-.25.212-.605.444-1.241.767-1.347.72-2.198.983-2.198.983s-1.617-.234-4.207-1.007c0 0 1.306-.378 1.93-.581a40.11 40.11 0 0 0 1.958-.681c1.055-.396 1.73-.761 2.18-1.088.03-.022.058-.046.085-.068 0 0 .32.036.593.113.294.083.604.245.786.386.191.147.28.308.308.358a.681.681 0 0 1 .071.226s.014.085-.003.177a.579.579 0 0 1-.147.313zM24 12.196a.662.662 0 0 0-.08-.157 1.348 1.348 0 0 0-.197-.23 1.685 1.685 0 0 0-.227-.178c-.354-.232-.81-.362-1.215-.416-.627-.083-1.342-.07-1.411-.07-.23-.005-1.722.007-2.105.015-1.702.034-3.787.039-4.333.038-5.636.027-8.089-.094-10.82-.642C1.289 10.094 0 9.658 0 9.658c2.05-.073 14.004-.568 16.186-.627 1.427-.04 2.44-.048 3.253 0 .413.023.802.058 1.287.14a6.2 6.2 0 0 1 1.064.286c.486.18.893.442 1.096.707 0 0 .06.06.14.17.093.126.197.282.234.34.294.447.434.73.484.828.052.102.1.209.145.315.044.104.063.166.076.21.02.064.03.125.035.17Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1013 B |
BIN
public/airline-logos/brussels-airlines.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
public/airline-logos/bulgaria-air.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
public/airline-logos/cargojet-airways.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
public/airline-logos/cargolux.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
public/airline-logos/caribbean-airlines.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
public/airline-logos/cathay-pacific.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
public/airline-logos/cebu-pacific.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
public/airline-logos/china-airlines.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
public/airline-logos/china-cargo-airlines.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
public/airline-logos/china-eastern.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
public/airline-logos/china-express-airlines.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
public/airline-logos/china-southern.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |