Inside the Sea Suite
Most of what you touch was made on the island or within a day's sail of it. Tap a point to read where it came from.

Heavy linen woven in Crete, dried on the roof so it smells faintly of salt and thyme.
Woven in Crete
Linen, washed in sea air
A room story told through its objects: numbered points sit on the photograph where each detail is, and choosing a point or a row in the numbered list beside it lights both up and opens a short note on where the piece came from, with list rules drawing in as the section arrives.
Numbered points pop onto a room photograph where each object sits, and hovering or clicking a point or its row in the numbered list beside it highlights both and expands a short note on where that piece came from.
Upgrade to Pro
Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.
Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.
Radix flavor
npx shadcn add "https://beste.dev/r/hotel24?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://beste.dev/r-base/hotel24?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/hotel24.tsx plus the text1 word stagger it uses for the heading.
The installed file exports hotel24Demo alongside the block: the exact props behind the preview above. Spread it to get a working section in one line.
import { Hotel24, hotel24Demo } from "@/components/beste/block/hotel24";
export default function Page() {
return <Hotel24 {...hotel24Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Hotel24 } from "@/components/beste/block/hotel24";
export default function Page() {
return (
<Hotel24
eyebrow="Inside the Sea Suite"
heading="Nothing in the room is there by accident."
description="Most of what you touch was made on the island. Tap a point to read where it came from."
image={{
src: "https://oud.pics/b/hotel/ostria-sea-suite.webp",
alt: "A linen bed facing a tall arched window that opens onto the sea",
}}
details={[
{ title: "Linen, washed in sea air", description: "Heavy linen woven in Crete, dried on the roof.", maker: "Woven in Crete", x: 26, y: 70 },
{ title: "The arched door", description: "Cut into a wall seventy centimeters thick.", maker: "Built in 1962", x: 72, y: 40 },
{ title: "A water jug from Sifnos", description: "Refilled with cold water every afternoon.", x: 93, y: 58 },
]}
labels={{ show: "Show detail" }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
eyebrow | string | – | Small uppercase line above the heading |
heading | string | – | Serif <h2>, staggered word by word through Text1 |
description | string | – | Paragraph at the right of the header |
image | Image | – | The room photograph the points sit on |
details | Detail[] | [] | One point and one list row per object |
labels | Labels | {} | Prefix for each point's accessible label |
className | string | – | Extra classes for the outer <section> |
type Image = {
src: string;
alt: string;
};
type Detail = {
title: string;
description: string;
maker?: string;
x: number; // percent from the left of the photo
y: number; // percent from the top of the photo
};
type Labels = {
show?: string;
};left: x% and top: y% and centered on that spot, so coordinates are percentages of the 4:3 photo frame, not pixels.maker line with a height animation.labels.show, its number and title, with aria-pressed on the active one; rows use aria-expanded, and a polite live region announces the active title.