尚未收集儲存庫資訊。
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗Three game-show front ends for choosing a January 2027 European break for two. All read the same researched spreadsheet, so they always show the same prices.
/january-getaway) is a tongue-in-cheek Saturday-night prize show: conveyor belt, guess the price, Keep / Maybe / Bin and a Grand Final./blind-flight) is a retro dating-show parody. Each episode hides three destinations behind a screen. The host asks them questions, each traveller secretly picks one, and only then are they unmasked./getaway-show) is a late-1980s Saturday-evening game-show parody: a tile-flip picture reveal, higher-or-lower price duels, a dartboard of wildcards, private two-person ballots and a grand final.All prices are indicative totals for two, observed on 23 October 2026. They are not live fares. Every price and link needs rechecking before you book.
The home page (/) lists every game. The January Getaway lives at /january-getaway, Blind Flight at /blind-flight and the Getaway Show at /getaway-show.
To add a game, give it its own folder under src/app/ and add an entry to src/lib/games.ts. Set comingSoon: true to show it on the home page before it is playable.
You will need Node 20 or later.
npm install
npm run dev # http://localhost:3000
npm test # data and logic checks
node tests/e2e/getaway-show.smoke.cjs # browser play-through; needs `npm start` running and Playwright installed
npm run typecheck
npm run build # production build, as Vercel runs it
| File | What it holds | How it changes |
|---|---|---|
data/source/January_2027_Europe_Holidays_Updated_Flexible_Flight_Times.xlsx | The authoritative workbook | Replace it with a newer version |
src/data/assumptions.json | Baggage per adult, transfers for two, observation date, travel window | Edit by hand |
src/data/itineraries.json | Every flight-and-room combination, normalised | Generated by npm run import-data. Do not edit by hand |
src/data/destinations.ts | Intros, highlights, cautions, typical January weather, photo paths, and which destinations appear in the show | Edit by hand |
src/data/imageCredits.json | Photographer and licence for each photo | Edit when you change a photo |
public/images/destinations/ | Destination photographs (Wikimedia Commons) | Add or replace JPEGs |
The importer reads two sheets:
Viable itineraries: 20 priced trips and 25 scheduled but unpriced trips.Connections to verify: 16 destinations with a room quote but no established flights.It recomputes each total as (fare per person × 2) + room + (baggage × 2) + transfers. It then checks the result against the workbook's own With extras / two column and warns about any mismatch. At present all 20 match to the penny.
A total is only produced when the workbook has a fare for those exact dates. Anything else has a null total. The site then shows "Flight price not verified" or "Needs manual review" and never borrows a price from another itinerary.
Viable itineraries sheet, or drop in a new workbook with the same sheet layout.npm run import-data.npm test. One test asserts that the recomputed totals equal the workbook's totals, so it will flag an edit made in only one place.pricesObservedOn in src/data/assumptions.json if the observation date has changed.Edit baggagePerAdultGBP or transfersForTwoGBP in src/data/assumptions.json, then run npm run import-data. The importer will warn that totals now differ from the workbook. That is expected. The data test will also fail until the workbook column agrees, which stops the two sources drifting apart without anyone noticing.
Each entry in src/data/destinations.ts has a role:
main: on the conveyor belt and in the price round. The default itinerary must be priced; a test enforces this.mystery: the bonus round. These have no matched fare, so the reveal says "Flight price awaiting confirmation".extra: Sensible mode only.The order of main entries is the order of the belt. A destination with several date or airport options gets one card with a date picker, not separate cards. Itineraries are attached automatically by destinationId. preferredItineraryId pins which one shows first; otherwise the cheapest priced option is used.
To add a destination, add a mapping in DESTINATION_IDS in scripts/import-holiday-data.ts, add an entry to destinations.ts, and rerun the importer.
Both contestants guess every priced prize. Each types a masked guess for two and locks it in, then the other takes the phone. Either can be skipped, and the price can be revealed at any point.
Points scale with the price: within 5% scores 10, within 10% scores 6 and within 20% scores 3. The closest guess that does not go over earns 2 more, shared on a tie. Points are entertainment only.
On a phone, the reasons to go, the caution and the weather fold away until the price is revealed. You can open them at any time.
Saves from the one-guess version keep their revealed guesses and points. An unrevealed guess from such a save is dropped, as it was never locked in.
Photos come from Wikimedia Commons under CC BY, CC BY-SA or CC0 licences. Credits are shown on each photo and listed in the site footer. If a photo is missing or fails to load, the card shows a designed poster-style fallback instead.
The brief is in docs/BLIND_FLIGHT_BUILD_BRIEF.md.
profiles.ts./blind-flight/final) starts with a second chance each: rescue one contestant nobody chose, or decline. Then you each choose the holiday in secret from everyone still standing. Agreement crowns the winner. In a split, the scoreboard leader may use a casting vote, or you can talk it over in the comparison.Quick play has one shared choice per episode and produces a shortlist, never a "match".
"I refuse to participate in this nonsense" opens Sensible mode at /blind-flight/holidays. It lists every itinerary in the travel window with filters for budget, nights, airport, trip type, price status and route.
| Route | Screen |
|---|---|
/blind-flight | Title screen and mode choice |
/blind-flight/show | All episodes and their outcomes |
/blind-flight/episode/[id] | One episode: questions, secret choices, handover and reveal |
/blind-flight/show/[id] | One contestant's full profile, once their identity is public |
/blind-flight/results | Matches, split decisions and the scoreboard |
/blind-flight/final | Second chances, the secret final choice and the winner |
/blind-flight/compare | Grand final comparison |
/blind-flight/contenders | More eligible contenders to add as a bonus round |
/blind-flight/holidays | Sensible mode |
/blind-flight/about | About these prices |
Every route works on reload, with Back, and when opened directly. Pages that depend on the whole show say so until every episode is decided.
| File | What it holds |
|---|---|
src/blind-flight/data/profiles.ts | Dating-show copy for each featured contestant: one-liner, three clues, pitch, awkward truth |
src/blind-flight/data/episodes.ts | Episode titles, presenter lines and casts |
src/blind-flight/data/copy.ts | Presenter copy bank and the host's three questions |
src/blind-flight/lib/cast.ts | Which trips can appear, variants per destination, episodes and cautions |
src/blind-flight/lib/cost.ts | Price breakdown and the quick-play duel badges |
src/blind-flight/lib/state.ts | Game state, actions and selectors |
src/blind-flight/lib/persistence.ts | Saving to localStorage, with a schema version and clean-up on load |
Facts are not duplicated. Names, countries, photos, highlights, typical weather and cautions come from src/data/destinations.ts. Prices, dates, flights, hotels and links come from src/data/itineraries.json. Update a price once with npm run import-data and both games pick it up.
cast arrays in episodes.ts. Shuffled shows draw on the same twelve contestants and take their titles from mixedEpisodes. The themed episodes still run as written for a show started before shuffling existed. Each destination needs a profile in profiles.ts with three clues. A test checks this. Clues run from broad to a strong hint. No one-liner or clue may name a city or country in the show, or a landmark that settles the guess. A test checks this against a list of giveaways in tests/blind-flight.test.ts.Connections to verify sheet have no established flights. They appear in Sensible mode only.State is saved under the blind-flight:v3 key with schemaVersion: 3. Saves from the old ballot version are ignored. A shuffled show saved before the balanced deal keeps its original line-up until it is reshuffled or reset. On load, anything unreadable, from another schema version, or pointing at a destination that no longer exists is dropped. Use Reset the whole show in the footer, or Start again on the title screen.
Two-person play works on one phone only. Nothing syncs between devices.
The brief is in docs/GETAWAY_SHOW_BUILD_BRIEF.md. It is broadcast on GBC, the Getaway Broadcasting Corporation, a fictional channel. Round names, artwork, lettering and presenter lines are original.
The quick edition has one shared ballot and gives Favourites, Maybes and Passes. It never calls anything a match. It also has one shared buzz per picture and one shared call per duel.
Studio points, price duels and the dartboard never change the ranking. Only votes do. Each traveller's studio points show after each round and on the results.
A show saved before the buzzers keeps its revealed pictures and its tiles. Its old "We got it" points named nobody, so they are dropped. An old shared price call counts for both travellers.
Every stage has Previous, Skip round, Go to sensible comparison and Enough nonsense — see the table. The lightning button skips animations; the speaker button turns on optional sound.
| Route | Screen |
|---|---|
/getaway-show | Title screen and pre-show |
/getaway-show/catch-a-flight | Round 1 |
/getaway-show/higher-or-lower | Round 2 |
/getaway-show/bullseye | Round 3 |
/getaway-show/vote | Round 4: ballots and handover |
/getaway-show/results | Results |
/getaway-show/final | Grand final and certificate |
/getaway-show/holidays | Every eligible itinerary, sortable and filterable |
/getaway-show/about | What the prices include |
| File | What it holds |
|---|---|
src/getaway-show/data/contestants.ts | Presenter setup, three clues, pitch and the catch for each featured destination; photo notes |
src/getaway-show/data/show.ts | Broadcast groups, the price ladder, board segments and board tags |
src/getaway-show/data/copy.ts | Presenter lines |
src/getaway-show/lib/cast.ts | Which trips can appear, date variants, duel trips and board pools |
src/getaway-show/lib/cost.ts | Price breakdown. Uses the workbook total once and never recomputes it |
src/getaway-show/lib/matching.ts | The two-person outcome rules |
src/getaway-show/lib/state.ts | Game state, actions and selectors |
src/getaway-show/lib/persistence.ts | Saving to localStorage under great-british-getaway-show:v3, with clean-up on load |
src/getaway-show/lib/summary.ts | Copy and share text |
Facts are shared with the other games. Names, countries, photos, highlights and typical weather come from src/data/destinations.ts. Prices, dates, flights, hotels and links come from src/data/itineraries.json.
broadcastGroups in show.ts. Each featured destination needs a full entry in contestants.ts. A test checks that the clues never name the city.priceLadder. Each card is compared with the one before it. Unpriced or repeated entries are dropped, so the number of duels follows the data.boardTags. "Cheap as chips" is worked out from prices (up to CHEAP_CEILING_GBP). "The curious wildcard" is every show destination with no priced trip.Taken at iPhone width (375 px) by the smoke test: docs/screenshots/getaway-show/.
| Title | Round 1 | Round 2 | Round 3 |
|---|---|---|---|
| Handover | Results | Grand final |
|---|---|---|
The app is a standard Next.js 15 App Router project. It needs no environment variables, database or API keys.
Each new game shuffles its running order: the conveyor belt and the mystery contestants here, and the Round 1 order, the Round 2 pairings and the board draws in the Great British Getaway Show. The shuffle is seeded and saved, so a refresh keeps the same order. It is fixed once anything has been judged or revealed. A game saved before shuffling existed keeps the workbook order until it is reset.
Guesses, decisions, the chosen dates, contestant names and settings are saved in the browser's localStorage. Nothing leaves the device. Progress survives a refresh but does not sync between phones. Use Reset the whole show in the footer to start again.
npm run lint. npm run typecheck and npm run build cover type and build errors.