← Back to Dovetail

[ Parable build guide ]

How Dovetail was built

A furniture studio, drawn the way a cabinetmaker draws. The signature is a canvas orthographic line-drawing of a lounge chair that rotates front → 3/4 → side as you scroll or drag — no textures, no 3D library, ~120 lines of vanilla JS.

static · no build stepcanvas 2DFraunces / Inter / Space Monolight + darkreduced-motion aware

The idea

Furniture photography flatters. A drawing tells the truth — it can't hide a proportion or a joint behind soft light. Dovetail leans all the way into that: the whole site is styled like a sheet of drawing paper, blueprint grid and all, and the hero is a dimensioned elevation rather than a hero shot. The promise is precision, so the site had to look measured.

The stack

Deliberately plain. One index.html, one styles.css, one main.js. No framework, no bundler, no CDN — the rotating drawing is hand-rolled canvas 2D, so the page has zero runtime dependencies and ships straight to GitHub Pages. Type is Fraunces (a warm, high-contrast serif with a craftsman's confidence) for display, Inter for body, and Space Mono for the technical meta a furniture drawing lives in — millimetres, Janka numbers, plate references.

Signature technique — the rotating elevation

The lounge chair is a tiny 3D wireframe — a seat slab, a reclined back and four splayed legs, built from boxes and prisms as arrays of edges. To draw it as a draughtsman would, we rotate every point about the vertical axis and project it flat with no perspective: drop nothing, foreshorten nothing, just spin and read off x and y. At 0° you see the front elevation; at 90°, the side.

// spin about the vertical (Y) axis, then project orthographically
const project = (p, s, c) => ({
  x: p[0] * c + p[2] * s,     // s = sin(angle), c = cos(angle)
  y: p[1],                    // height is untouched -> H is constant
  depth: -p[0] * s + p[2] * c // kept only to fade far lines
});

// scroll maps the section's progress to the target angle...
target = p * (Math.PI * 0.56);          // 0deg -> ~101deg
// ...and every frame eases toward it (a soft-close drawer):
angle += (target - angle) * 0.12;

Because height is never rotated, the overall-height dimension on the left stays a constant 820 mm, while the bottom dimension recomputes the projected width live — so the read-out ticks up from the chair's width toward its full depth as it turns. The four material chips swap the stroke colour (theme-aware, so walnut never disappears on a dark ground) and rewrite the spec caption underneath.

Details that matter

The commission form is a demo — it validates and confirms in-place but sends nothing. Wire it to your own endpoint (Formspree, a serverless function, an email service) before taking real orders.

Ship it on GitHub Pages

Nothing to build. Push the folder and point Pages at the root.

gh repo create bswxyz/dovetail --public --source . --push
gh api --method POST /repos/bswxyz/dovetail/pages -f 'source[branch]=main' -f 'source[path]=/'

Relative paths and a .nojekyll file mean it serves from the project subpath without a single config change. That's the whole point of the static build — the drawing does the work.

← Back to Dovetail