Skip to content
Web Development1 June 2026 · 7 min readUpdated 30 September 2026

Horizon: A Space Tourism Website Template, Explained

A close read of Horizon, my single-page space tourism website template: its structure, the faint scroll-driven background tint, the video weights and reduced-motion handling, checked against the deployed source.

Horizon: A Space Tourism Website Template, Explained

If you're weighing a space tourism website template, or you want to build a scroll-driven one-page site for a product that deserves a cinematic first screen, this is a close read of Horizon, one of my web templates. Open the live demo, scroll slowly once, then view the page source while you read. Everything below was checked against the deployed files on 2026-09-30, and I've corrected a few things an earlier version of this post got wrong.

One label up front: the prices, statistics, testimonials and dates inside Horizon are invented placeholder copy for a demo. Nothing on it describes a real spaceflight operator, a real booking or a real customer.

What does a space tourism website template include?

A space tourism website template like Horizon is a single-page brochure: a video hero, six destination cards with spec panels, a membership band, a flight log, a partners marquee and a booking request form, all filled with fictional content. The job of the page is to make a visitor want to click "Reserve a seat".

The hero carries the headline "Venture past our sky", a one-line subtitle about private passage to orbit and the Moon, that call to action, and two stat tiles counting up to 34.5 minutes to orbit and 2.8B km mapped. Both numbers are placeholders. A section rail on the side tracks scroll progress.

The destinations are the core of the page. Each of the six has a name, a coordinate band, a demo price, a duration, an altitude, a gravity figure, a seat count and a one-sentence description, and the gallery lets the visitor pick one to open its panel. The demo values:

DestinationCoordinates (demo)Price (demo)Duration (demo)
Low OrbitLEO · 420 KM$280,0006 hours
Aurora StationPOLAR · 540 KM$640,0003 nights
Deep FieldHEO · 35,786 KM$1,150,0004 nights
Lunar GatewayL2 · 384,400 KM$2,400,0005 nights
Halo RingNRHO · 71,000 KM$3,800,0009 nights
Solar DriftL1 · 1.5M KM$6,200,00014 nights

Between the destinations and the form, a header comment in the source lists a hero "portal warp" transition and a spacecraft "explode" section built from a component called ExplodeCube. I haven't described those in detail because the scroll tint and the video are the parts worth copying first. Below that sit three membership tiers (Orbit, Lunar and Charter, the last priced "On request") and three flight-log quotes that are placeholder text. The page ends with a form headed "Request your manifest" that asks for name, email, destination, preferred window and number of travelers.

That form does nothing on the server. Its submit handler only flips a flag in the browser so a "Manifest received." message appears. If you reuse the template, wiring the form to a real backend is your first job, and it is deliberately a brochure rather than a checkout.

How is the Horizon template built?

Horizon is a static site: one HTML file loads React 18.3.1 and @babel/standalone 7.29.0 from unpkg, then compiles six JSX files in the visitor's browser, and styles everything with one hand-written stylesheet of about 54 KB uncompressed. There's no build step and no Tailwind.

The six files split the work in a readable way. helpers.jsx holds the interpolation function, a shared animation loop and the reduced-motion flag. premium.jsx holds the custom cursor, the preloader, the section rail and the scroll progress bar. sections.jsx holds the stats band, the membership tiers, the flight log and the background tint. App.jsx assembles the header, hero, destinations and booking form, with OrbitImages.jsx and ExplodeCube.jsx supplying the two special components. If you fork the template, that split tells you where to look for each behaviour.

Plain CSS suits a page that leans on a few bespoke gradients, a scroll-driven background and a circular destination gallery, which are awkward to express as utility classes. A real stylesheet can cost less to maintain than a thousand class strings, though that's a judgment call, not a rule.

The trade-off is in the script tags. The page loads the development builds of React, and compiling JSX in the browser is something the Babel docs discourage for shipping sites: they say that if you're using Babel in production you should normally not use @babel/standalone, and they point to a build system instead. Babel's @babel/standalone page frames it as a tool for prototyping and demos. That fits a template demo well. For a customer site, my recommendation is to precompile the JSX and switch to production builds of React before launch.

The source isn't fully clean for reuse either. Comments in the code flag a "demo storefront link" that should be removed before you deploy your own instance, and the menu overlay carries placeholder contact and location lines. Treat those as a checklist.

How does the scroll-driven background colour work?

A component called BackgroundTint turns scroll progress into an RGB value and writes it to the body's background colour, blending between five stops. The effect is deliberately faint: every channel stays between 4 and 14 out of 255, so the page drifts between near-blacks with a slight blue lean.

An earlier version of this post described a warm beige and a slate, and that was wrong for the source deployed today. These are the actual stops:

Scroll progressRedGreenBlue
0 (top)555
0.22867
0.464612
0.708514
1 (bottom)556

Progress is scrollY divided by the scrollable height, clamped between 0 and 1, and a small piecewise-linear interpolation helper blends the channels. The write itself is a single line:

document.body.style.backgroundColor = `rgb(${r},${g},${b})`;

To adapt it to your own brand, edit the three arrays and keep the stops in the same order. Keep the values close together if you want the background to read as atmosphere rather than as a visible colour change; widen them and the shift becomes a feature visitors notice.

Does the scroll handler need throttling?

Probably not for one style write, but two details are worth knowing. The listener is registered as passive and runs on every scroll event, and it reads scrollHeight each time, which can force layout. Caching that value and refreshing it on resize would be cheaper. That is my suggestion and I haven't profiled it.

An earlier version of this post suggested moving the update into requestAnimationFrame. MDN's scroll event page says scroll events can fire at a high rate and handlers shouldn't run computationally expensive DOM work, but it also calls rAF-based throttling of scroll handlers useless, because animation frame callbacks fire at the same rate as scroll events. MDN's requestAnimationFrame reference confirms the callbacks usually match the display refresh rate. So if you need to throttle, measure a timeout yourself, and otherwise keep the handler cheap.

How heavy is the hero video, and what about reduced motion?

The hero clip is 655,884 bytes, about 641 KiB, while the two other background clips are 989,512 and 4,279,338 bytes, measured with HTTP HEAD requests on 2026-09-30. The heavy one is the third clip, so that's the file to recompress first.

Each background video uses autoplay, muted, loop and playsinline. web.dev's guide on replacing GIFs with video recommends exactly that attribute set so a video behaves like an animated GIF. A video hero is still unusual: the HTTP Archive Web Almanac 2024 media chapter reports that 6.7% of mobile pages and 7.7% of desktop pages include at least one <video> element, and that autoplay appears on 23% of video elements. That's a statistic about video in general, not about heroes, so read it as context rather than a benchmark.

Motion is where a cinematic template can go wrong. MDN describes prefers-reduced-motion as the way to detect that a user wants less non-essential motion, and notes that scaling or panning large objects can trigger vestibular discomfort. Horizon reacts in two ways: a script checks the media query and sets the background video's opacity to 0 when reduce is on, and the stylesheet shortens animation and transition durations to almost nothing. One limit follows from the code: the script reads the query once when the page loads, so changing the operating-system setting mid-visit needs a reload.

How can you verify all this yourself?

  1. Open the demo and reload with the Network tab filtered to media, then compare the three file sizes with the numbers above.
  2. Scroll the page with the Elements panel open and watch the style attribute on body change.
  3. Turn on reduced motion in your operating system or emulate it in DevTools, reload, and check that the hero video is hidden.
  4. Read the six JSX files linked from the page source and compare them with this description.
  5. Check the stylesheet size in the Network tab against the 54 KB figure, and treat any difference as a sign the template has changed since I measured it.

If you want the wider story of how I package templates, start with Building Web Templates: Design, Engineering, and Selling. For a sibling build with a different design problem, see Echo, the musician portfolio template. Your next step: pick one of the six destination panels and rewrite it for your own product, then see whether the page still holds together without the space theme.

Free resource

Free SaaS MVP Scope Template

A Notion document with the full feature checklist, MVP vs. nice-to-have table, pre-build questions, and cost signals — so you walk into any developer call knowing exactly what to ask for.

Get the template →
DL

Dusko Licanin

Full-Stack Developer · Banja Luka, Bosnia

Full-stack developer shipping SaaS MVPs, web apps, and mobile apps using AI-augmented workflows — without agency coordination overhead. Live portfolio: BookBed, Callidus, Pizzeria Bestek.

Frequently Asked Questions

What does the Horizon space tourism website template include?

Horizon is a single-page demo with a video hero, six destination cards with spec panels, three membership tiers, a flight log, a partners marquee and a booking request form. Every price, statistic, testimonial and date in it is invented placeholder copy. The form only shows a confirmation message in the browser, so it needs a real backend before you use it for requests. Comments in the source also flag a demo storefront link that should be removed from your own deployment.

How does the scroll-driven background colour work in Horizon?

A component called BackgroundTint computes scroll progress, interpolates red, green and blue between five stops, and writes the result to the body's background colour. The stops stay between 4 and 14 out of 255, so the change is a faint drift between near-black tones. The scroll listener is passive and runs on every scroll event. MDN notes that throttling a scroll handler with requestAnimationFrame is useless, so keep the handler cheap or measure your own timeout.

Is the Horizon template ready for production use?

It is a demo-grade template, and you should harden it before using it for a real client. It loads development builds of React and compiles JSX in the browser with @babel/standalone, which the Babel docs say you should normally not do in production. Precompile the JSX, switch to production React builds, replace the placeholder copy, connect the booking form to a backend and recompress the heaviest background video, which measured about 4.3 MB on 2026-09-30.

Does Horizon respect prefers-reduced-motion?

Partly, and it is worth testing. A script reads the prefers-reduced-motion query once at page load and hides the background video when reduce is on, and the stylesheet shrinks animation and transition durations to almost nothing. Because the script reads the query only once, changing the operating-system setting mid-visit needs a reload. MDN notes that scaling and panning large objects can trigger vestibular discomfort, which is why a cinematic page should treat this setting seriously.