Appendix — for the curious
How the catalogue was drawn.
NORRLAND has no photographs. Every piece of furniture on the main page is a hand-written SVG line illustration that assembles itself when it scrolls into view, and comes apart into a labelled exploded view when you hover or ask. This appendix explains the joinery of the page itself.
01The concept
A printed catalogue that behaves like a workshop.
The site plays a small Swedish furniture workshop — eight pieces, honest woods, a six-week lead time — and borrows its visual language from two schools at once: Scandinavian design-shop minimalism (warm white paper, hairline rules, enormous whitespace, one dusty-blue accent) and the technical catalogue illustration you find in old joinery manuals: consistent 2 px ink lines, elevations drawn to real dimensions, dashed hidden-lines for the joinery you can't see.
The constraint that shaped everything: no photographs allowed. When you can't photograph the furniture, you have to understand it well enough to draw it — where the tenons go, which way the wedges drive, what a trestle actually carries. The signature interaction falls out of that honesty: furniture that is drawn as parts can assemble, and anything that assembles can explode.
02Technique
Drawing furniture in SVG.
Each piece is a plain elevation (side view for chairs, tables and daybeds; front view for shelves and benches) inside a shared 240 × 240 viewBox. Proportions come straight from the stated dimensions: the Vindel chair is 52 cm deep and 78 cm tall, so at 2.2 px/cm its drawing is 114 units wide and 172 tall. Because every card renders at the same width, one stroke-width: 2 reads identically across all eight drawings.
Every part is a <g class="part"> — a leg, a seat, a wedge key — filled with a quiet wood tone and stroked in ink. Joinery you can't see from outside is drawn as 1 px dashed “hidden lines”, the way a joiner would pencil them:
<!-- back leg + post: one raked quad, drawn to the rake of the real chair -->
<g class="part" style="--ady:26px; --d:.08s; --edx:8px; --edy:14px">
<path class="d fx-birch" pathLength="1"
d="M172 206 L150 36 L142 36 L164 206 Z"/>
</g>
<!-- the tenons hiding inside the seat -->
<path class="hid" d="M73 114 V107 M78 114 V107"/>
The custom properties on each part are its entire choreography: --adx/--ady is where it assembles from, --edx/--edy is where it explodes to, and --d is its place in the queue.
03Technique
The assembly sequence.
Two animations run together when a drawing enters the viewport. The strokes draw themselves — pathLength="1" normalises every shape's length to 1, so a single CSS rule animates any path, rect, circle or ellipse from invisible to drawn. And the parts travel home — legs rise from below, seats drop from above, stretchers slide in sideways — each on its own --d delay, in roughly the order a joiner would actually assemble the piece: legs, stretcher, seat, back.
.piece .d {
stroke-dasharray: 1; /* pathLength="1" makes this universal */
stroke-dashoffset: 1;
transition: stroke-dashoffset .8s ease var(--d, 0s);
}
.piece .part {
opacity: 0;
transform: translate(var(--adx, 0px), var(--ady, 0px));
transition: transform .72s cubic-bezier(.2,.85,.25,1) var(--d, 0s),
opacity .5s ease var(--d, 0s);
}
.piece.on .d { stroke-dashoffset: 0; }
.piece.on .part { opacity: 1; transform: none; }
An IntersectionObserver adds .on at 30% visibility. About 1.7 s later, JavaScript adds a second class, .settled, which zeroes out all the stagger delays — so the entrance is choreographed, but the exploded view afterwards responds instantly instead of re-queuing behind six transition delays. That one-line class swap is what makes the same transforms feel like two different systems.
04Technique
The exploded view.
Exploding is just a third destination for the same transform. Parts separate along their real assembly axes — wedge keys lift out of their mortises, shelves lift off their pegs and slide sideways, the mirror glass comes forward out of its rabbet — because the offsets were chosen per part, not applied as a generic scatter. A .callouts layer of dotted leader lines and part labels fades in on top; labels live in the drawing's margins, top and bottom, so they never sit on the ink.
/* button (works everywhere, incl. touch + reduced motion) */
[data-card].exploded .piece.on .part {
transform: translate(var(--edx, 0px), var(--edy, 0px));
}
/* hover — only for pointers, only if motion is welcome */
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
[data-card]:hover .piece.on.settled .part {
transform: translate(var(--edx, 0px), var(--edy, 0px));
}
}
Under prefers-reduced-motion, every drawing arrives pre-assembled — no drawing-on, no travel — and the exploded view still works, as an instant state change through the button only. Try it here:
Fig. A — Kalix stool, live1 : 8
05Provenance
How it was made.
This site was built by Claude (Fable 5) writing vanilla HTML, CSS and JavaScript by hand — no frameworks, no build step, no image files. All eight furniture drawings, the wood-grain swatches and the paper texture are inline SVG; the whole shop is two HTML documents. The workshop, its founder, and its address are fiction; the joinery is real.
It is one of twenty-five sites in a showcase of what current models can do in web design. The rest of the collection lives at fable-25-dhb.pages.dev.
06Steal this
Take these home.
-
pathLength="1" is the whole draw-on trick.
Put it on any SVG shape and
stroke-dasharray: 1; stroke-dashoffset: 1 → 0animates it — nogetTotalLength()JavaScript, no per-path measurements, circles and rects included. -
Choreograph with custom properties, not keyframes.
Give each moving element inline
--from,--toand--delayvariables and let two or three shared CSS rules read them. Eight illustrations, ~40 parts, zero @keyframes. -
Add a “settled” state after entrances finish.
Entrance stagger feels wonderful once and laggy forever after. A class added by
setTimeoutthat zeroes the delays lets the same transforms power both a choreographed entrance and an instant hover response. -
Explode along assembly axes.
Exploded views read as craftsmanship when each part moves the way it would really come apart — wedges up out of mortises, shelves up off pegs — and as decoration when everything just drifts outward.
-
Keep labels off the ink.
SVG text is inside the same coordinate system as the drawing, so reserve margins (top and bottom bands work best) for callout labels and let only the dotted leader lines travel toward the parts.