The making of this site
How this site was woven
The structure here is drawn in code — the loom in the hero is a fragment shader, the icons are single threads of SVG, the section edges interlock like cloth. In its second edition the site also gained photographic plates, generated with an image model and woven into the same cloth. This guide explains both, honestly and completely, so another designer could weave their own.
Creative direction
The page is a loom
Makers Intelligence serves seamstresses, weavers, braiders — people whose work is literally made of thread. So the metaphor is not decoration; it is the layout system. The page composes as horizontal strips, like cloth coming off a kente loom: ivory strips for reading, full-bleed emerald strips for chapters that need weight, and gold only ever as a thread running through — never as a slab.
Even the transitions between sections obey the metaphor: strip edges interlock with rounded warp-thread tabs instead of meeting in a straight line. Scroll the home page slowly and you can watch each band being woven into the next.
The palette is cut from the same cloth: deep emerald grounds, warm gold wefts, ivory for air, and a clay accent used the way a weaver uses a contrast thread — sparingly, on purpose.
Type: one serif, worked hard
Fraunces is a variable font with an optical-size axis, which means the same family can be a soft, wonky display face and a sharp small-caption italic. We push that axis to both extremes on purpose — it is the typographic version of thick and thin thread from one spool. Archivo carries the interface and body text underneath it.
Brand identity
A monogram made of thread
The mark is an M whose uprights are the warp — the vertical threads a loom holds in tension — and a single gold weft passing across it: over the uprights, under the diagonals, the way plain weave actually interlaces. The wordmark sets “Makers” in Fraunces with the ™ tucked high, like a maker’s label stitched into a hem.
Six services, one continuous thread
Each of the six things Makers carries gets an icon drawn in the same voice: a single stroke weight, round caps, no fills — as if each icon were bent from one length of wire, or sewn in one run of the machine. On scroll they draw themselves in like thread pulled through cloth.
The pattern, derived from the mark
Tile the monogram’s grid — warp bars crossed by two gold wefts — and you get the brand pattern used on story-card corners and this page’s header. One drawing, three jobs: mark, motif, texture.
Signature technique
The loom shader, explained
The hero is a single fragment shader on a raw WebGL context — no Three.js, no library, about 8 KB of hand-written code. Every pixel decides for itself whether it belongs to a vertical warp thread, a horizontal weft thread, or the gap between them.
1 · A grid of threads
Divide the canvas into columns and rows about 15–30 px wide. Within each cell, the fractional position gives a thread profile: a rounded highlight via sqrt(1 − x²) so each thread reads as a soft cylinder, not a flat stripe. Colours come from a hash of the thread index, grouped into bands of four so neighbouring threads share a shade — that banding is what makes it read as kente rather than a checker.
2 · Plain weave, one line of math
Real cloth interlaces: each warp goes over one weft, under the next. In a shader that is a parity test — and shading whichever thread goes “under” with the other thread’s curve makes the interlace read as depth:
// column ci, row ri — who is on top at this crossing?
float warpTop = mod(ci + ri, 2.0);
if (warpTop < 0.5) {
c = mix(c, warpC * (0.62 + 0.38 * abs(wpy)), warpA); // warp dips under
c = mix(c, weftC, weftA);
} else {
c = mix(c, weftC * (0.62 + 0.38 * abs(wpx)), weftA); // weft dips under
c = mix(c, warpC, warpA);
}
3 · The shuttle weaves it in
On load, only the warp hangs there, dim and slack. A progress uniform sweeps a “weaving front” down the canvas, and each weft row switches on as the front passes — alternating direction row by row, the way a shuttle actually travels. Rows above the front brighten as the cloth tightens:
// rTop: row index from the top · sx: position along the row,
// flipped on alternating rows like a shuttle pass
float t = u_weave * (rowsTotal + 10.0) - rTop;
float sx = mix(uv.x, 1.0 - uv.x, mod(rTop, 2.0));
float weftOn = smoothstep(0.0, 0.22, t - sx);
4 · A hand near the cloth
The cursor doesn’t push pixels — it bows the threads. Sample positions are displaced away from the pointer with an exponential falloff (exp(−distance × 3.2) × 9px), so the cloth seems to dimple around your hand, and a faint gold shimmer follows like lamplight on silk. The pointer is smoothed with a simple lerp so the cloth feels heavy, not jumpy.
What it costs, and the fallback
- Device pixel ratio is capped at 2; the render loop pauses when the hero scrolls off-screen or the tab hides.
- Under
prefers-reduced-motion— or wherever WebGL is unavailable — the canvas is never started; a static woven-cloth SVG pattern takes its place. Same cloth, at rest. - The whole thing costs one draw call of a full-screen triangle per frame.
Layout system
Section edges that interlock
Between every pair of bands sits a thin strip whose background is the band above, with the band below rising through it as rounded tabs — a CSS mask-image holding a tiny inline SVG of four staggered warp threads, repeated horizontally. Two custom properties tell each strip which colours it is joining:
/* <div class="weave-edge" style="--above:…;--below:…"><i></i></div> */
.weave-edge { height: clamp(22px, 3.4vw, 40px); background: var(--above); }
.weave-edge i { position: absolute; inset: 0; background: var(--below);
mask-image: url("data:image/svg+xml,…four rounded rects…");
mask-size: 96px 100%; mask-repeat: repeat-x; }
It costs two elements and zero JavaScript, works at any width, and quietly carries the thesis: the sections aren’t stacked, they’re woven.
A lesson we learned
Drawing icons through the shadow DOM
The icons live once in the document as <symbol> definitions and are placed with <use>. Our first build styled them with .t-icon path { stroke: … } — and in the first design-critique screenshots every icon rendered as a solid black blob. The reason is worth knowing: CSS selectors cannot reach inside a <use> element’s shadow tree, so the paths never got their strokes; they fell back to SVG’s default black fill.
The fix is to stop selecting the paths and instead set inherited SVG presentation properties on the host <svg> — fill, stroke, stroke-dasharray and friends all cascade through the shadow boundary:
.t-icon { fill: none; stroke: currentColor; stroke-width: 2.4; }
/* every path carries pathLength="1", so one rule draws any icon: */
.js .t-icon.draw { stroke-dasharray: 1 1; stroke-dashoffset: 1;
transition: stroke-dashoffset 1.6s var(--ease-out); }
.js .t-icon.draw.in { stroke-dashoffset: 0; }
pathLength="1" is the quiet hero: it normalises every stroke to the same unit length, so the dash math never needs to know how long a path really is. When an icon scrolls into view, an IntersectionObserver adds .in and the whole icon sews itself in.
Second edition
The photographic plates, honestly
The first edition of this site was entirely code-drawn — a constraint of its environment that became a creative thesis. The second edition was allowed photography, and the client asked for the one thing typography could not deliver: the makers themselves. So the site gained six photographic plates: three persona portraits, a diaspora studio, Accra at dusk, and a macro of kente on the loom.
Every plate is AI-generated (Higgsfield Soul, a photorealistic image model). No real person is depicted anywhere on this site. That is stated on the page where the portraits appear, in the footer, and here — because a product built on trust cannot decorate itself with an ambiguity.
Art direction: one shoot, not six pictures
Every prompt carries the same house grade — golden-hour light, warm deep-emerald and antique-gold palette, shallow depth of field, dignified documentary craft photography — so the set reads as a single commissioned session, not a scatter of stock. People are photographed mid-craft, hands working, never posed at the camera; the register is dignity, not pity and not gloss.
Contact-sheet review
Generated imagery betrays itself in lettering first, then in hands. Every frame was reviewed at full size like a contact sheet; frames with garbled signage, brand lettering on a machine, or an embroidered pseudo-logo were rejected and reshot with tighter constraints. Four of the first six frames failed this review. The reshoots did not.
Joining the weave
Photography enters through the site’s own furniture, never as naked stock: each plate carries a woven selvedge — the surface below rises through the photo’s bottom edge as rounded warp tabs, the same mask that interlocks the page’s bands — plus a quiet emerald-and-gold grade layered over the image so every frame sits inside the palette, and a thread caption set in the caption italic. The code-drawn spine (shader, map, dashboard, icons) is untouched.
Delivery
Plates ship as responsive WebP pairs (full-width and 800 px) behind srcset, lazy-loaded below the fold with explicit dimensions, so the whole second edition costs a phone well under half a megabyte of imagery.
Toolchain & pipeline
How it was actually made
This site was designed and art-directed by Hannah Kwakye and engineered with Fable 5, Anthropic’s frontier model, working as a designer-engineer under direction — writing the HTML, CSS, GLSL and JavaScript by hand, taking screenshots, critiquing them, and iterating. No page builder, no framework, no template.
- Static, hand-authored HTML/CSS/JS. Zero libraries, zero runtime requests to third parties. The interactive machinery is IntersectionObserver, a rAF loop, and one WebGL context.
- Self-hosted variable fonts. Fraunces (upright + italic) and Archivo, subset to woff2 at build time and served from
/assets/fonts— never from Google’s CDN. The display font is preloaded. - The structural visuals are code-drawn. That began as an environment constraint — no stock photos, no generated rasters — and became the creative thesis of the first edition: if you can’t borrow warmth, you have to build it. The loom, the map, the dashboard, the icons: all SVG, CSS and shader. The second edition added photographic plates — AI-generated, art-directed as one golden-hour shoot, reviewed frame by frame, delivered as responsive WebP. No real people are depicted.
- Vercel, CI-driven. Push to deploy; immutable caching on
/assets/*; security headers invercel.json; the waitlist posts to a form endpoint (FormSubmit) with a honeypot field and an inline success state.
Accessibility & performance, concretely
- Semantic landmarks, one
h1per page, a skip link, and:focus-visiblestyles throughout; decorative SVG isaria-hidden, informative SVG carries real labels. prefers-reduced-motionis a first-class path: the shader never starts, reveals appear without translation, the icon and map draw-ins render complete, and transitions drop to 120 ms.- Animations touch only
transform,opacityand stroke offsets — nothing that provokes layout. Parallax is capped at ±40 px. - First view is about 200 KB transferred, all three font files included — the shader hero costs kilobytes, not megabytes, which is the point of writing it raw.
Iteration protocol
Four passes, logged honestly
Every site in this collection goes through the same discipline before it ships: screenshot everything at three widths, critique it as if it were someone else’s work, act on the findings — then push two things further, then hunt down whatever is broken. Here is what each pass actually changed on this site:
-
Pass i. Design critique
- The thread icons were rendering as solid black fills — CSS can’t select into
<use>shadow trees. Restyled them with inherited presentation properties on the host SVG (the fix documented above), which also made the draw-in animation actually work for the first time. - The hero eyebrow was set in clay red on the dark loom — handsome on ivory, illegible on emerald. Switched it to light gold and deepened the scrim’s left side so the lede clears the brightest weft band.
- Fast scrolling could shoot past a section before its reveal fired, leaving cards invisible; the observer now also reveals anything already scrolled past, so no viewer can outrun the loom.
- The thread icons were rendering as solid black fills — CSS can’t select into
-
Pass ii. Elevation
- The hero headline now rises word by word out of the weave — each word masked in its own clipping span, staggered 75 ms apart, skipped entirely under reduced motion.
- The “Born in Ghana” map gained weft packets: gold shuttles that travel the arcs from Accra outward once the threads have drawn in — SMIL motion started by JavaScript only when motion is allowed.
- The workroom dashboard’s sparkline now weaves itself in when the section arrives, endpoint blinking on last — a small thing, but it makes the mock feel alive without a single fake metric changing.
-
Pass iii. Ship quality
- Every route, anchor, form state and cross-link tested; the waitlist form verified with its honeypot, inline success message, and
?successreturn path. - Zero console errors at every width on all three pages; reduced-motion verified with the shader replaced by the static cloth and all draw-ins pre-completed.
- Proofread every word — including the GLSL comments — and confirmed the pre-launch honesty notes (illustrative personas, founding pricing) survive on every page that needs them.
- Every route, anchor, form state and cross-link tested; the waitlist form verified with its honeypot, inline success message, and
-
Pass iv. Second edition — the makers arrive
- The review verdict was blunt: a product for makers showed zero hands, zero cloth, zero workshops. Six photographic plates were commissioned from an image model under one art direction — golden-hour, emerald and gold, hands mid-craft — and the persona initials-in-a-square became portraits.
- “Born in Ghana” opens on Accra at dusk with gold threads drawn over the photograph in SVG, and a kente macro band now breaks the long ivory stretch before the stories. Every plate is framed by the woven selvedge and a thread caption, so photography joins the identity instead of replacing it.
- Four of the first six frames failed contact-sheet review (garbled signage, a pseudo-logo, awkward hands at the loom) and were reshot. Honesty labels — on the page, in the footer, and in this guide — say plainly that all photography is AI-generated and no real people are depicted.
- Copy widened with the casting: the same system that holds an Osu order wall now names a London loft and a Brooklyn chair; scroll reveals were hardened so deep links and restored scroll positions never land on an empty viewport.
See it on the loom
The best way to read this guide is with the site open beside it — watch the bands interlock, bow the threads with your cursor, and see the icons sew themselves in.