Naar de inhoud
fusionstudios.
Luchtvaartcodes2026Eigen project

FlyCodes

FlyCodes is een eigen project van FusionStudios: een snelle, gratis opzoekmachine voor IATA- en ICAO-codes van luchthavens en luchtvaartmaatschappijen. We bouwden er een volledig naslagwerk omheen, van 8.803 luchthavens tot 6.000 routepagina's, dat statisch is en waarvan het zoeken in de browser van de bezoeker draait.

Bekijk live →
FlyCodes, luchtvaartcodes website ontworpen door Fusionstudios

De uitdaging

Wie "AMS airport code" opzoekt wil één regel antwoord. In de praktijk krijgt diegene een cookiemuur, een paar advertentieblokken en een tabel die pas na een seconde inlaadt. De vraag is klein en exact, het aanbod eromheen is traag en rommelig. Daar komt een strategisch probleem bij. De kop van deze markt is bescheiden, dus de winst zit niet in het hoofdterm maar in de lange staart van duizenden losse luchthavens en maatschappijen. Die staart is alleen te bedienen als de pagina's echte, eigen data dragen in plaats van een ingevuld sjabloon, en dat op een schaal waar handwerk niet meer kan.

Onze aanpak

We kozen voor een site die het antwoord sneller geeft dan een netwerkverzoek. De zoekindex met 9.911 records wordt eenmalig opgehaald, daarna gebeurt het zoeken in de browser: geen zoek-backend, geen database, geen API-call op het moment dat iemand typt. Publieke open datasets (OurAirports en OpenFlights) worden bij de build omgezet in getrimde JSON, de zoekindex en een statische JSON-API. Dat gebeurt met twee scripts: een Python-pijplijn voor luchthavens, maatschappijen, landen en banen, en een Node-script voor de routes. Daaromheen ontwierpen we een eigen merk- en designsysteem, codenaam TERMINAL MIDNIGHT, dat het vertrekbord als visuele grammatica neemt. Geen template, geen CSS-framework, geen gekocht thema. De zoekbalk, de pagina's en de OG-afbeeldingen komen uit datzelfde systeem.

Het resultaat

De site prerendert ruim 12.700 HTML-pagina's plus ruim 9.900 statische API-bestanden, gebouwd op Next.js 16 en React 19 met TypeScript in strict mode en drie runtime-dependencies: next, react en react-dom. De pagina's dragen hun eigen titel, metadescription, canonical en JSON-LD, en op de luchthaven-, maatschappij- en routepagina's wordt de Open Graph-afbeelding opgebouwd uit de data van die pagina zelf. De kwaliteit wordt niet met het oog bewaakt maar met scripts. Een linkchecker loopt de gebouwde site na op gebroken interne links en op vaste pagina's die nergens meer vandaan gelinkt worden. Een validator trekt de JSON-LD uit de HTML en controleert die op structuur. Daarnaast staat er een contrastcontrole op WCAG AA, die de kleuren rechtstreeks uit het tokenbestand leest, en een SEO-baseline die routes, titels, metadescriptions, koppen en structured data vergelijkt met een vastgelegde snapshot. Ze hangen niet aan een CI-pijplijn: het zijn commando's die we draaien voordat een ronde werk de deur uit gaat. Wat er staat is af, lokaal geverifieerd en klaar om door te groeien.

Resultaat

Ruim 12.700 statische pagina's en ruim 9.900 API-bestanden, opzoeken in de browser

Waarom uitgerekend luchthavencodes

Een luchthavencode opzoeken is een van die vragen waarbij het antwoord korter is dan de vraag. AMS is Amsterdam Schiphol, de ICAO-variant is EHAM, klaar. Toch is de gemiddelde pagina die dat antwoord geeft zwaarder dan een nieuwsartikel. Dat is precies het soort scheefstand waar we naar zoeken bij onze eigen projecten: een exacte, veelgestelde vraag met een aanbod dat er structureel niet bij past.

De strategische reden is dezelfde. Het hoofdterm rond IATA-codes is bescheiden in volume en redelijk competitief, dus daar wordt de wedstrijd niet gewonnen. De echte markt is de optelsom: 8.803 luchthavens en 1.108 maatschappijen, elk met hun eigen handvol zoekopdrachten ("AMS airport code", "what airport is AMS", "Amsterdam airport code"). Stuk voor stuk lage moeilijkheid, samen een substantieel geheel.

Die redenering werkt alleen als je de staart ook echt kunt bedienen. Een pagina per luchthaven bouwen is triviaal; duizenden pagina's bouwen die elk iets unieks te melden hebben is dat niet. Dat is de eigenlijke opgave geworden, en die bepaalde de meeste keuzes die daarna volgden.

TERMINAL MIDNIGHT: het vertrekbord als ontwerpsysteem

Voor het merk lag er één beeld voor de hand dat nog niemand in deze niche serieus had genomen: het vertrekbord. Codes hóren op een bord. Het brandbook noemt de positionering "de departure board voor de hele planeet", en dat is geen decoratie maar de bron van het hele systeem. Het palet is dark-first: nachtblauw (--bg #0b1220) met één signaalkleur, amber (--accent #ffb020), volgens een strikte 60-30-10-verdeling. Amber is gereserveerd voor de primaire actie, actieve staten en codes, want als amber overal zit is het nergens.

De typografie doet hetzelfde werk. Archivo voor kop en interface, B612 Mono voor codes en data, een lettertype dat letterlijk getekend is voor Airbus-cockpitdisplays. Codes staan in kapitalen met tabular figures, zodat een kolom cijfers niet gaat dansen. Het logo is een split-flap-tegel die halverwege de omslag stilstaat en zo een F vormt, met de naad dwars door het glyph. De signatuur van de site is de FlapPlaceholder in de zoekbalk, die echte codes doorloopt zoals een bord dat doet.

Er zit geen Tailwind of ander framework in. De kleuren en maten staan in één tokenbestand (app/tokens.css) en de rest van de CSS leest daaruit; de contrastcontrole parseert datzelfde bestand, zodat de gecontroleerde waarden en de uitgeleverde waarden dezelfde zijn. Depth komt van 1px lijnen en verschoven tinten, niet van zachte schaduwen. Beweging is mechanisch, met een lineaire easing voor het tikken van de flaps, en prefers-reduced-motion is in de stylesheet verwerkt. De boardvlakken blijven donker in beide thema's, ook in de lichte variant, om de simpele reden dat een bord een bord is.

Statisch tot in de kern

De techniek is Next.js 16 met de App Router, React 19 en TypeScript in strict mode. Wat in de package.json misschien nog het meest zegt: er staan drie runtime-dependencies in, next, react en react-dom. Verder niets. Geen ORM, geen zoekdienst, geen analytics-SDK, geen UI-bibliotheek.

Dat is geen minimalisme om het minimalisme. Het opzoeken gebeurt in de browser, over een index van 9.911 records (8.803 luchthavens plus 1.108 maatschappijen) van ruim een halve megabyte, die één keer wordt opgehaald op een idle moment of bij de eerste toetsaanslag, zodat de eerste paint er niet op wacht. Vanaf dat moment gaat er bij het typen geen verzoek meer de deur uit: wat iemand opzoekt blijft op het apparaat, simpelweg omdat er geen zoekserver is die het zou kunnen ontvangen. De lettertypen worden bij de build gedownload en vanaf onze eigen origin geserveerd, zodat er ook geen runtime-verzoek naar een CDN van Google gaat.

Verzoekloos is de site daarmee niet, en die nuance hoort erbij: het contactformulier post naar een externe endpoint en de afstandscalculator haalt een eigen statisch coördinatenbestand op. De belofte geldt waar het telt, bij het opzoeken zelf. Dezelfde logica loopt door in de features. "My Board", waar bezoekers luchthavens kunnen pinnen, en de recente opzoekingen leven in localStorage, met een maximum van 24 en 8 items. Geen account, geen synchronisatie, geen profiel. De routepagina's rekenen hun afstanden ter plekke uit met een great-circle-formule op de coördinaten die al in de dataset zitten, en de vluchttijd is een expliciet als schatting gelabelde berekening: 30 minuten overhead plus cruise op een bewust lage 800 km/h, afgerond op 5 minuten en met een ondergrens van 35, in plaats van een geleend cijfer.

Van 8.803 luchthavens naar ruim 12.700 pagina's

De data komt uit publieke bronnen: OurAirports (publiek domein) voor luchthavens, banen en landen, OpenFlights voor maatschappijen en routes. Twee build-scripts doen het werk: een Python-pijplijn leest de ruwe CSV- en DAT-bestanden en schrijft daar getrimde JSON, de client-side zoekindex en ruim 9.900 losse JSON-bestanden uit die samen een gratis API zonder sleutel vormen, terwijl een Node-script de 6.000 routes samenstelt. Bronnen en licentie staan op een eigen /data-pagina, want bij dit soort werk is herkomst onderdeel van de geloofwaardigheid.

Niet iedere luchthaven krijgt een pagina, en dat is een bewuste rem. Eén functie in de code beslist wie in aanmerking komt: een bruikbare IATA-code plus daadwerkelijke dienstregeling of de status groot of middelgroot. Dat levert ruim 5.300 luchthavenpagina's op, drukste eerst, naast ruim 1.100 maatschappijpagina's, 236 landenpagina's, 53 stadspagina's, tien dataset-gedreven ranglijsten en 6.000 curated routepagina's. Met de vaste en redactionele pagina's erbij komt de laatste build uit op ruim 12.700 geprerenderde pagina's. De volledige dataset van 8.803 luchthavens blijft bereikbaar via de zoekindex en de API, ook waar geen losse pagina staat.

Diezelfde rem zit op de routes. Elk luchthavenpaar zou een pagina kunnen zijn, maar dat is een kwadratische explosie die niemand dient. Dus zijn de 6.000 drukste paren voorgerenderd en indexeerbaar, terwijl elk ander paar nog wel op aanvraag rendert (de afstandscalculator werkt voor alles) maar op noindex staat. Het soort detail dat bepaalt of een programmatische site na een jaar nog gezond is. En dan zijn er de kleine hoekige dingen die je alleen op deze schaal tegenkomt, zoals de luchthavencodes CON, AUX en NUL: dat zijn stuk voor stuk Windows-apparaatnamen die als bestandsnaam niet mogen bestaan, dus krijgen ze in de API een onderstreep mee. Hetzelfde geldt voor de reeksen COM1 tot en met LPT9.

Vindbaarheid als constructie, niet als laagje

De pagina's worden bij de build gegenereerd, dus wat de crawler binnenhaalt is de volledige pagina en geen leeg omhulsel dat nog moet worden ingevuld. Elke paginasoort bouwt zijn eigen titel, metadescription, canonical, Open Graph- en Twitter-kaart op uit de data die eronder ligt. Titels worden niet afgekapt met een slice maar gekozen uit een ladder van kandidaten binnen een budget van 50 tekens, zodat de code heel blijft en de optionele hook eerder sneuvelt dan het antwoord.

De structured data is per paginatype opgebouwd als een @graph: op luchthavenpagina's een Airport-object met PostalAddress en GeoCoordinates, plus een FAQPage en een BreadcrumbList. De sitemap is gesplitst in zes shards via generateSitemaps (statisch plus hubs, luchthavens, maatschappijen, landen, steden en routes) met een statische sitemap-index erboven, omdat één sitemap op deze omvang geen goed idee is. De OG-afbeeldingen komen uit next/og en worden getekend met de gegevens van de pagina zelf: een routetegel draagt de twee codes, de afstand en de geschatte vluchttijd. De maatschappijpagina's krijgen die afbeelding allemaal al bij de build, net als de 500 drukste luchthavens en de 200 drukste routes; de staart daarachter rendert bij de eerste opvraging aan de edge en blijft daar gecached, zodat de build niet duizenden afbeeldingen hoeft te tekenen.

Naast de pagina's staan er drie linkbait-assets: de gratis JSON-API zonder sleutel als ontwikkelaars-aas, een insluitbare zoekwidget met een "Powered by FlyCodes"-link, en een interactieve kaart van de drukste luchthavens. De API is ook beschreven in een llms.txt. Daaronder ligt de set verificatiescripts. Het verify-commando draait de linkchecker en de JSON-LD-validator over de gebouwde site: een gebroken interne link laat het falen, net als een vaste pagina of een artikel waar niets meer naartoe wijst. Voor de lange staart van luchthavens, maatschappijen, landen, steden en routes is een ontbrekende inbound link bewust een waarschuwing en geen fout, want die pagina's worden via zoeken en via de sitemap gevonden. De contrastcontrole en de SEO-baseline draaien we los daarvan; die laatste bestaat omdat een redesign alles mag veranderen wat een bezoeker ziet, maar niet wat Google leest.

Waar het nu staat

FlyCodes is gebouwd en lokaal geverifieerd. De build gaat schoon door de scripts, het domein flycodes.net zit in de configuratie gebakken, het merk staat vastgelegd in een brandbook waar de tokens uit volgen, en de groeirichting (naar de volle 8.803 luchthavens) ligt uitgeschreven klaar. De laatste ronde werk staat gecommit en wacht op uitrol. Er zitten geen advertenties in en er is geen aanmelding; zowel de advertentiecomponent als de consent-balk die in de code staan renderen niets tot iemand ze bewust aanzet, dus de cookiemuur waar de case mee opent is er nu domweg niet.

Voor een opdrachtgever is dit vooral een bewijsstuk van reikwijdte. Dit is geen site die we hebben ingericht, het is er een die we van nul hebben bedacht, gepositioneerd, ontworpen, gebouwd, van data voorzien en vindbaar gemaakt, inclusief de saaie onderdelen: de contrastcontrole, de titelbudgetten, de sitemap-shards, de bestandsnamen die op Windows niet mogen bestaan. Wij bouwen dit soort werk zelf en onderhouden het zelf, en dat is een ander vak dan een thema aankleden.

Wat FlyCodes daarnaast laat zien is een houding. Een site kan snel, privacyvriendelijk, toegankelijk en eigenzinnig zijn zonder dat een van die vier de andere drie opeet. Dat vraagt keuzes die geld noch tijd besparen op de korte termijn, zoals een eigen designsysteem in plaats van een framework, of een rem op je eigen paginagroei terwijl je er duizenden bij zou kunnen drukken. Het zijn precies die keuzes die bepalen of iets over twee jaar nog staat.

Volgende caseUnitGlide

Klaar om jouw merk te laten groeien?

Vertel ons over je project. We denken graag met je mee, vrijblijvend.

5.0 op Google · 8 reviewsLive binnen 5 weken
Start een project

Vrijblijvend. Je hoort binnen één werkdag van Jamey.

Liever eerst even sparren? App of bel Jamey op 06 40866279.

BellenWhatsAppStart een project