# Boutique Hotel Template

> A boutique hotel website with a dark-green contents rail, a photographic room explorer, a walking-distance guide and a three-step enquiry journey. Designed for hotels, B&Bs, guesthouses, country retreats and wedding venues.

Canonical: https://gsapvault.com/templates/boutique-hotel-template
Live demo: https://gsapvault.com/demos/boutique-hotel-template/index.html

| Property | Value |
|----------|-------|
| Type | template |
| Tier | paid |
| Price | £10 |
| Difficulty | advanced |
| Plugins | ScrollTrigger |
| Techniques | tab-panel, crossfade, scroll-reveal, parallax, keyboard-navigation, range-input, anchor-scroll, sticky, smooth-scroll |
| Uses Lenis | Yes |

## Lighthouse, as measured

Google Lighthouse on the demo, 9 September 2026. A measurement of the demo as shipped, not a promise for your page.

| Category | Score |
|----------|-------|
| Accessibility | 100 |
| Best practices | 100 |

No performance score is published: it depends on the deployment (server compression, caching, CDN, connection and device) rather than on the code, so measure it where it will live.

## Overview

An expansive photographic website for boutique hotels, guesthouses and country retreats. Marlowe House is its worked example: fourteen rooms above Bath, a warm dining room and places to explore on foot. Large serif headings, a dark-green contents rail and richly scaled photography give the whole page the atmosphere of a house worth staying in.

Explore six rooms through photographs that move across a large exterior scene. Each selection brings its room description, rate and booking link into view. Broad dining photographs and an image-rich walking guide continue the visit before a three-step enquiry journey.

The site ships as editable HTML, CSS and JavaScript with local WebP photographs. Change its imagery, room details, palette and copy for a B&B, country house hotel, inn or wedding venue.

## Features

- A dark-green monogrammed contents rail with numbered chapters beside an expansive photographic cover
- A room explorer that keeps its selector and large photograph visible together on desktop, with a sticky swipeable room index on phones
- Room selection by hover, click, touch and arrow keys, including Home and End
- Smoothly interrupted room transitions and one-time text reveals that preserve their baseline
- Large dining, breakfast, local-guide and house photographs
- Walking-distance dial with immediate destination results, a live count and links into the photographic guide
- A three-step enquiry journey: dates and room, guest details, then an editable review, with a live photographic stay summary
- Fifteen locally bundled, graded WebP photographs and an editable source manifest
- Complete stacked rooms without JavaScript and instant changes under reduced motion
- Optional Lenis scrolling on the shared GSAP clock
- Required-field and date validation, retained values when going back, and an explicit demonstration completion with no submission

## Use Cases

- Boutique hotels and country house hotels with several room types worth comparing
- Bed and breakfasts, guesthouses and farm stays that want to sell on the rooms
- Small inns and pubs with rooms, and restaurants with rooms
- Wedding and event venues showing the house and the grounds
- Design-led serviced apartment houses and members' clubs
- Any bookable place sold on photographs, a walk from the door and a plain enquiry

## Questions about this template

### It's a hotel in the demo. What else does this design suit?

Anything bookable and sold on its rooms, its house and its location: a boutique hotel, a bed and breakfast or guesthouse, a country house hotel, a small inn or pub with rooms, a farm stay, or a wedding and event venue. The register is six rooms here, but each entry is a photograph, a caption, four figures and a floor, so they become six suites, six cottages or six event spaces by editing the text. Nothing in the layout says hotel except the words.

### Does the enquiry form actually send anything?

No. This is a three-step demonstration: choose a room and dates, enter guest details, then review and edit the enquiry. Required fields and date order are checked, and values survive going back. Completion clearly says that nothing was sent or reserved. Connect it to your booking engine, Formspree, Netlify Forms or CRM before using it for real enquiries.

### How do I add, remove or reorder the rooms?

Each room has a matching index entry and photo panel. Copy the pair and give them the same new key, then replace the photograph, floor label, description and figures. Add the room to the enquiry select as well. You can present suites, cottages or event spaces in the same explorer, with the house photograph providing the setting.

### Can I use my own photographs, and what happens to the fifteen included?

Yes. The fifteen photographs are locally bundled WebP derivatives from Pexels and Unsplash. Replace the files or update the source manifest and regenerate them. The room photographs use a landscape 4:3 crop at 1400 by 1050, and the exterior is 1920 pixels wide. Keep the main subject within the centre of the crop so it also reads on phones.

### Can I change the house photograph behind the rooms?

Yes. The exterior photograph appears both on the cover and behind the room explorer, giving the two sections a shared sense of place. Replace cover.webp with a broad landscape photograph of your property. Each room moves within the scene on desktop; on mobile it stays in place so its details remain easy to read.

### Does the walking dial work on a phone and with a keyboard?

Yes. The walking guide uses a native range control, so a finger, mouse or keyboard can change the distance. Places within that radius receive the brass marker and full-strength photograph. Destination photographs remain visible on phones, making the guide useful as a visual introduction to the neighbourhood as well as a list of walking times.

### I want a different accent colour and typeface. How much is there to change?

The palette and two font families are defined at the top of the stylesheet. Change the ivory grounds, ink, brass and dark dining surface together with their RGB values. Keep the pale labels on photographs and the cover scrim so text remains readable over your new images. The included contrast notes explain the intended use of each colour.

## Vibe-Code Ready Setup

This template includes `START-HERE-AI.md`, a product-specific copy-paste setup prompt for Cursor, Claude Code, ChatGPT, GitHub Copilot, Windsurf, and other coding assistants. It tells the assistant to inspect the existing stack, integrate the supplied files, preserve the design, scope selectors, retain accessibility and responsive behaviour, add framework-appropriate GSAP cleanup, and report what it tested.

[How AI-assisted setup works](https://gsapvault.com/vibe-coding)

## How It Works

### A photographic house visit

A fixed contents rail accompanies the cover, rooms, dining, walking guide and enquiry. Wide photographs and large serif headings carry the identity. Every section can be edited or removed independently.

### Explore the rooms

Choose a room to bring its photograph, description, figures and booking link into view against the house scene. Changes glide smoothly between positions on desktop and stay within a fixed frame on phones. Keyboard navigation offers the same selection as pointer and touch.

### The local guide and enquiry

Adjust the walking distance to see which places are within reach. The enquiry guides visitors through their room and dates, contact details and an editable review, while a photograph and summary reflect the chosen stay. It validates required fields and dates but does not send an enquiry or reserve a room.

### Static and reduced-motion views

With JavaScript disabled the six rooms form a complete, readable sequence. With reduced motion enabled the controls still work, changes apply immediately and photographs remain still. Text remains visible when animation dependencies cannot load.

## Documentation

How this template works and how it goes into a page. The reference you use once you own the files (worked examples, events, the programmatic API, the class list) ships with the download.

### Quick Start

**1. Upload the folder.** `index.html`, `assets/style.css`, `assets/script.js`
(or `assets/script.min.js`) and `assets/img/` are the whole site. Any static host
will do.

**2. Check the `<head>`.** Three things must stay, in this order:

_Code snippet omitted: it ships with the download._

That one-line script must stay synchronous and stay in `<head>`. It is what stops
every reveal target painting visible for a frame and then flashing to zero.
`data-cfasync="false"` stops Cloudflare Rocket Loader deferring it, which would
bring the flash back on the live site only.

**3. Keep the scripts before `</body>`:**

_Code snippet omitted: it ships with the download._

**4. Swap the fifteen photographs and rewrite the copy.** Everything else is
optional.

---

### Using It With Your Own Design

The page is one long printed sheet, so the fastest reskin is to decide what your
place is and let the copy do the work. Four changes carry most of it:

- **The name and the colophon.** The wordmark in the rail, the `h1` on the cover
  in the `.cover__name` heading,
  and the one-line colophon under it.
- **The token block.** Nine solids at the top of `assets/style.css`, each with
  its RGB triple. Every rule, dimmed label, floor label, scrim and focus ring on
  the page is one of them at another alpha.
- **The photographs.** Drop your own files into `assets/img/` with the same
  names, or edit `assets/img-manifest.json` and re-run the bake.
- **The register.** Six rooms, each one index row plus one stage entry, joined by
  a key such as `garden`. Copy both blocks and rename the key.

Nothing in the layout says "hotel" except the words, so the same page becomes a
B&B, a country house hotel, a small inn or pub with rooms, a farm stay or a
wedding venue by editing the copy and the room names.

---

### Sections and their options

Each section is initialised by its own function and every one returns early when
its markup is missing, so you can delete any section from `index.html` without
touching the JavaScript.

| Section | Hook | What you can change |
|---|---|---|
| Cover | `.cover` / `#top` | The two name copies, the colophon, and the photograph. The photograph's height is `.cover__media` in CSS; the paper name is clipped to it by script. |
| The register | `[data-reg]` / `#rooms` | Each `[data-reg-tab="key"]` index row is joined to a `[data-reg-panel="key"]` entry. Copy a pair to add a room. Each panel carries an opaque floor label and a landscape photograph. |
| The table | `#table` | Plain markup: the supper list with prices, the hours, the note and the two photographs. The `[data-drift]` image drifts on scroll. |
| Around | `#around` | Each `li.around__row` carries `data-min` (the walk time) and a brass dot, a minute, a place, a line and an optional small photograph. The dial's range is `min`/`max`/`step`/`value` on `[data-dial-range]`. |
| The house | `#house` | Five `.house__fact` definition rows and the figure row. The photograph is sticky beside them on desktop. |
| Enquire | `#book` / `[data-book-form]` | The rate line, the contact, and the form fields. The room `<select>` options must use the same keys as the register if the "Book this room" links are to set them. |

#### The register

The six rooms begin life as six complete entries in the markup, so with
JavaScript off they stack as a plain list of rooms with their own plates,
captions and figures. With motion allowed the section adds `.is-live` and the
entries stack in one grid cell to become a tablist.

- **Inputs.** Pointer hover on a fine pointer, click and tap, and the arrow keys
  with Home and End over a roving `tabindex` (`aria-selected` and `tabindex`
  move with the selection; the inactive panels take `inert`).
- **The transition.** Opacity changes and the panel's position ease from their
  current values. Rapid input retargets the current transition without jumping
  to the previous endpoint. Desktop positions are in the `positions` array in
  `initRegister`; mobile uses a fixed position. Keep positions between 0 and 9
  with the default 91% panel width to retain clearance inside the scene.
- **The house scene.** `.reg__house` holds the large exterior photograph.
  Each room has a `.reg__floor` label. Replace `assets/img/cover.webp` to change
  the exterior in both the cover and explorer. No SVG elevation is required.
- **Book this room.** Each entry carries a link with `data-book-room="<key>"`.
  It sets the value of the enquiry's room `<select>` and the ordinary in-page
  scroll carries the visitor to the form.

#### The cover

The name is a single heading over the exterior photograph. A dark CSS scrim
keeps it legible. Its entrance changes opacity only; scroll reveals likewise
run once and never reset or translate text when the visitor reverses direction.

#### The walking dial

`#around` hides its dial until the script shows it, so with JavaScript off the
dial is absent and every row shows at full strength. The dial is a native
`<input type="range">`: a finger drags it, a tap jumps, and the arrow keys, Home
and End move it a step. Each update toggles `.is-in` / `.is-out` on the rows
whose `data-min` is inside or beyond the radius — the brass dot, the brass
minute and the full-strength photograph for the ones inside, a hairline and a
dimmed photograph for the rest — and writes the count out in
`[data-dial-count]`.

#### The enquiry journey is not wired

The enquiry uses three `data-step` fieldsets: stay, guest details and review.
`initBook` owns progression, back and review-edit controls, validation and the
live photograph. Inputs keep their values when changing steps. Room links from
the explorer update the select and dispatch change so the summary stays current.
Dates use local calendar values; departure must follow arrival. Required fields
and email validity are checked before advancing. Review values are inserted as
text, including the optional guest note.

The final action completes a demonstration only. Nothing is transmitted or
reserved. Connect the final submit branch to your booking engine or enquiry
endpoint to collect real requests, and handle server validation and responses.
Without JavaScript all input fieldsets remain readable; the interactive actions
are hidden. Reduced motion keeps all steps usable without the transition.

The dark sidebar has numbered section links, an active dot and a stay action.
Mobile uses the existing keyboard-accessible drawer. The room index and image
share a desktop grid row; below 961px the index is a sticky horizontal scroller.
The walking scale's labels use the same 10px endpoint inset as its 20px thumb. A live result list directly beneath the slider shows every destination within reach, with links to the photographic guide. Its reserved height prevents the guide moving when results change.

### Palette

Nine solids and their `--*-rgb` triples at the top of `assets/style.css`: the
paper `#F3EEE4`, the register band `#E9E2D4`, the ink `#1D1B18` with two dimmed
steps, the brass accent `#865D1E`, the night band `#1E1B17`, and the lifted
accent `#D8A657` that exists only for the band. Repaint them and the site
reskins.

Measured as used, composited, at the size it is used:

| Pair | Ratio | Notes |
|---|---|---|
| ink on paper | 14.9:1 | the name, chapter heads |
| ink-dim on paper | 6.7:1 | body copy, captions |
| ink-faint on paper | 5.2:1 | 12px labels — the floor |
| ink-faint on the register band | 4.95:1 | the same labels on paper-2 |
| brass on paper / on the register band | 5.05:1 | links, figures, the floor label |
| paper on brass fill | 5.05:1 | the Book now bar, the Send button |
| paper on night | 14.9:1 | the dining band |
| paper-dim / paper-faint on night | 9.4:1 / 7.1:1 | band body and labels |
| brass-lift on night | 7.8:1 | menu prices, the band's one accent |

Brass is never set as text on the night band (it measures 2.1:1 there; the lift
exists for it) and never sits on a photograph. Over the cover photograph the
light name is `--paper` against a dark scrim. The cover scrim darkens the photograph beneath the text; retain it with replacement imagery.

Type: Gilda Display (display, 400) and Overpass (text, 400/500/600). The name is
the page's largest object; chapter heads sit around a 3.4:1 ratio against body
copy, and the label at 12px is the only small type.

---

### Images

Fifteen bundled photographs in `assets/img/`, about 2MB in total, all WebP
graded as one set: saturation 0.80–0.86 and a few degrees toward red, with a
small brightness lift per image. The originals are never redistributed.

- Swap photos: replace the files in `assets/img/`, or edit the source URLs in
  `assets/img-manifest.json` and re-run
  `bun scripts/build-template-assets.ts boutique-hotel-template`.
- Shapes, so replacements crop well: the cover is 1920×1280 landscape, the six
  room plates are 1400×1050 landscape, the dining room is 1600×1067, the breakfast
  photograph is 900×600, the five place photographs are 720×540, and the stair
  hall is 1400×1050. The room plates are cropped by nothing — they are placed at
  their own ratio — so a landscape room photograph with the bed centred will
  survive any column width.
- Exterior: [Unsplash source](https://images.unsplash.com/photo-1464146072230-91cabc968266), under the [Unsplash licence](https://unsplash.com/license).
- Interior and local photographs (Pexels licence, free to use):
  - The Garden Room: https://www.pexels.com/photo/7746559/
  - The Little Room: https://www.pexels.com/photo/34838628/
  - The Terrace Room: https://www.pexels.com/photo/7524883/
  - The Corner Room: https://www.pexels.com/photo/7546638/
  - The Great Room: https://www.pexels.com/photo/37884161/
  - The Attic Room: https://www.pexels.com/photo/38881363/
  - The dining room: https://www.pexels.com/photo/32568165/
  - Breakfast: https://www.pexels.com/photo/27083015/
  - The river and the weir: https://www.pexels.com/photo/31020423/
  - The bookshop: https://www.pexels.com/photo/13012320/
  - The café: https://www.pexels.com/photo/17331980/
  - The bar: https://www.pexels.com/photo/30691575/
  - The path over the wall: https://www.pexels.com/photo/33595563/
  - The stair hall: https://www.pexels.com/photo/16899825/

---

### Accessibility

Keyboard: the register is a real tablist — click, the arrow keys, Home and End
all select a room, and the active tab and panel carry `aria-selected` and
`inert` correctly. The walking dial is a native range input, so the keyboard path
is built in. Every link, button, field and the room `<select>` are real controls
with a visible focus ring; the enquiry's nights count and the dial's count are
announced through live regions, so no state is only visual.

The phone menu is a `<button>` that reports `aria-expanded`, moves focus into the
rail when it opens, closes on Escape or on the scrim, returns focus to the button
that opened it, and stops Lenis while it is open.

Reduced motion is a complete static page: the reveals are restored, the register
and the dial still work with every change applied instantly, and the band
photographs are left still.

Without JavaScript the head gate is removed and the page is a plain printed
document: the six room entries stack complete with their plates, captions and
figures, the dial is hidden and every row shows at full strength, the cover name
sits on the paper, and the rail is a working list of in-page links. The same is
true if the CDN is blocked — `initTemplate` takes `has-js` back off so nothing is
left hidden.

---

### Dependencies and teardown

GSAP 3.15.0 (core and ScrollTrigger) and Lenis 1.3.17, both from CDN. The
script's one `gsap.context()` owns every animation and ScrollTrigger; the
matchMedia branch returns a cleanup that removes the listeners it added and
destroys its own Lenis instance, leaving any host Lenis in place. Lenis can be
switched off per page with `data-smooth="off"` on `<html>` or `?smooth=off` in
the URL.

## What You Get

- `index.html`: working demo page
- `assets/script.js`: commented, readable source
- `assets/style.css`: effect styles
- `README.md`: full documentation with examples and framework integration notes
- `START-HERE-AI.md`: product-specific copy-paste prompt for AI-assisted setup
- `LICENSE.txt`: standard license terms
- Lifetime updates: re-download anytime from your library

## Get the Code

This is a premium template. The standard license costs £10 one-time and covers unlimited personal and commercial projects with no attribution required. The only restrictions: no redistribution of the code itself and no competing effect libraries.

- [Buy Boutique Hotel Template](https://gsapvault.com/templates/boutique-hotel-template)
- [The Vault (£99 one-time, best value): everything in the catalogue, including future releases](https://gsapvault.com/effects)

---

From [GSAP Vault](https://gsapvault.com): production-ready GSAP animation effects. Full catalog for agents: https://gsapvault.com/llms-full.txt
