The drawing
Every piece starts full size on paper. We keep drawing until the proportions stop arguing with us, sometimes for weeks.
Ashgrove Workshop, chairs and tables made by hand
A short story in five parts from our workshop by the river, where six of us make around two hundred pieces a year.
Every piece starts full size on paper. We keep drawing until the proportions stop arguing with us, sometimes for weeks.
We buy whole trees from two mills we know by name, then let the boards rest in the loft for a year before the first cut.
No screws and no metal. Mortise, tenon and a little glue, cut by hand so the frame stays tight for decades.
Three coats of hard wax oil, rubbed in by hand and left to cure between each one. It looks like nothing, which is the point.
Then it leaves us. We ask for a photograph a year later, to see where the light falls on it.
Made slowly, for everyday use.
A pinned scroll feature section for a furniture workshop built on the scroll-rail component: the heading, intro, an Arrow Pill and an underline link open a long editorial story that travels sideways as the page scrolls. Five chapter spreads follow, each with a large photograph that moves slower than its frame, a faint oversized chapter numeral drifting behind the text, and a short title and paragraph that brighten as the spread reaches the middle. Portrait and landscape spreads alternate with the photograph above or below the text, and a quiet closing line with its own button ends the rail. Reduced motion turns the rail into a plain horizontal scroll.
A pinned section where an intro panel and a row of numbered chapter spreads travel sideways on the scroll-rail component as the page scrolls, each photograph drifting inside its frame and each chapter's text brightening as it reaches the middle.
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://ui.beste.co/r/feature312?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/feature312?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/feature312.tsx plus the scroll-rail component and the button23 and button2 buttons it uses.
The installed file exports feature312Demo alongside the block: the exact props behind the preview above. Spread it to get a working chapters rail in one line.
import { Feature312, feature312Demo } from "@/components/beste/block/feature312";
export default function Page() {
return <Feature312 {...feature312Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Feature312 } from "@/components/beste/block/feature312";
export default function Page() {
return (
<Feature312
eyebrow="Ashgrove Workshop, chairs and tables made by hand"
heading="How a chair gets made."
description="A short story in five parts from our workshop by the river."
buttons={[
{ label: "Visit the workshop", href: "/visit" },
{ label: "Read the full story", href: "/journal" },
]}
chapters={[
{
title: "The drawing",
text: "Every piece starts full size on paper.",
image: {
src: "https://images.unsplash.com/photo-1718981464703-c167144381eb?w=1600&q=80",
alt: "Drafting table covered with sketches and measuring tools",
},
shape: "landscape",
photo: "top",
},
{
title: "The joints",
text: "Mortise, tenon and a little glue, cut by hand.",
image: {
src: "https://images.unsplash.com/photo-1503602642458-232111445657?w=1600&q=80",
alt: "Pale oak chair against a white wall",
},
shape: "portrait",
photo: "bottom",
},
]}
closing="Made slowly, for everyday use."
closingButton={{ label: "Order a piece", href: "/order" }}
rail={{ gap: 112, align: "center", smoothing: 0.5 }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
eyebrow | string | – | Muted line above the heading in the first panel |
heading | string | – | Section heading, rendered as an h2 |
description | string | – | Intro paragraph under the heading |
buttons | ActionButton[] | [] | The first renders as an Arrow Pill (Button23), the rest as underline links (Button2) |
chapters | Chapter[] | [] | One spread per chapter, numbered 01, 02 and on in order |
closing | string | – | Large last line on the rail |
closingButton | ActionButton | – | Arrow Pill under the closing line |
rail | Omit<ScrollRailProps, "children" | "progress" | "autoplay" | "className"> | – | Forwards the ScrollRail props from the scroll-rail component (gap, align, speed, smoothing, paused) |
className | string | – | Extra classes for the outer <section> |
type ActionButton = {
label: string;
href: string;
};
type Chapter = {
title: string;
text: string;
image: { src: string; alt: string };
/** Frame proportion of the photograph */
shape?: "portrait" | "landscape";
/** Photograph above or below the text */
photo?: "top" | "bottom";
};360svh tall with a sticky stage of 100svh minus 78px (at least 640px); scroll progress between 0.02 and 0.96 is clamped to 0 to 1 and handed to the rail as a live progress value, with autoplay forced off.data-rail-depth="0.22", so it drifts against the travel inside its clipped frame, and the faint 01 style numeral behind the text drifts faster at 0.4.data-rail-focus="0.35": they sit at 35% opacity away from the middle and brighten to full as their panel is centered.shape: "landscape" widens a spread to 46rem from md (portrait is 26rem), and photo: "bottom" flips it with flex-col-reverse; on phones every panel is 85vw.h3.closing or closingButton is set.