Why the patterns are there
The background pattern on tadreej.org's homepage is a twelve-pointed star rosette — a tessellation found on the walls of the Shah Jahan Mosque in Thatta, Pakistan, built in 1647. On the Reconstruction pages, a simpler six-pointed star pattern references the Ibn Tulun Mosque in Cairo, built in 879 CE. A third pattern, based on the eight-pointed stars of the Great Mosque of Córdoba (784 CE), appears in other sections.
These are not decorative choices. Islamic geometric art is one of the most sophisticated mathematical traditions in human history — a tradition that developed concepts of symmetry, tessellation, and infinite repetition centuries before European mathematics formalised them. For a project grounded in the intellectual heritage of Islamic civilisation, the patterns are an argument made in geometry rather than prose.
The question was: how do you render them on the web without making them a performance liability?
How Islamic geometric patterns work
The construction method for these patterns has been documented since at least the 10th century. The basic principle:
-
Start with a star polygon. A regular polygon with vertices connected by chords that skip a fixed number of points. The Shah Jahan pattern uses a {12/5} star — a twelve-pointed star where each vertex connects to the point five positions away.
-
Tile the plane. Place copies of the star at regular intervals on a grid. For twelve-pointed stars, the grid is square. For six-pointed stars, hexagonal.
-
Compute intersections. The chords of adjacent stars cross each other, creating intersection points. These intersections define the vertices of the interlocking shapes — the kite-like petals, the smaller polygons that fill the gaps between stars.
-
Extract the pattern. Clip the geometry to a single tile. The tile, when repeated, produces the infinite tessellation.
The mathematics is exact. Given the star polygon notation and the tiling grid, every intersection point can be computed from first principles using polar coordinates and line-line intersection formulas.
The first implementation: runtime computation
Our initial implementation followed the classical construction method literally:
"use client";
function buildTile(S: number): string {
const paths: string[] = [];
// For each star in a 5×5 neighbourhood
for (let tx = -2; tx <= 2; tx++) {
for (let ty = -2; ty <= 2; ty++) {
const cx = tx * S + S / 2;
const cy = ty * S + S / 2;
const R = S * 0.5;
// Generate 12 chords of the {12/5} star polygon
for (let i = 0; i < 12; i++) {
const a1 = (i * Math.PI * 2) / 12;
const a2 = ((i + 5) * Math.PI * 2) / 12;
const x1 = cx + R * Math.cos(a1);
const y1 = cy + R * Math.sin(a1);
const x2 = cx + R * Math.cos(a2);
const y2 = cy + R * Math.sin(a2);
// Clip to tile boundary, find intersections...
paths.push(`M${x1},${y1}L${x2},${y2}`);
}
}
}
// Filter, deduplicate, clip to unit tile
return paths.join(" ");
}
This generated a 5×5 grid of overlapping stars, computed all chord intersections, clipped to a single tile boundary, and returned the SVG path data. The full Shah Jahan implementation was about 160 lines of trigonometry, line-line intersection math, and polygon clipping.
Mathematically, it was beautiful. Each run reproduced exactly the construction that a 17th-century craftsman would have performed with compass and straightedge.
But it was also pure computation on every page load — wrapped in useMemo, running in the browser, requiring the "use client" directive and React hydration before any pattern could appear.
The insight: geometry is a pure function
buildTile(100) returns the same 9KB string every time. The star polygon {12/5} has exactly the same intersections regardless of when or where you compute them. The mathematics hasn't changed since the Abbasid period.
There is no reason to recompute this on a mobile phone in Peshawar every time someone opens the homepage.
We ran the computation once, captured the output, and embedded it as a static constant:
// Pre-computed {12/5} star polygon tile at unit size 100×100
const TILE_PATH = "M81.7,100.0L79.9,98.2 M79.9,98.2L77.8,96.1 ...";
// (9KB of SVG path data — the complete Shah Jahan tessellation tile)
Scaling without recomputation
The tile is computed at a fixed 100×100 unit size. To render it at any actual size — 220px for the hero, 100px for dividers, 120px for sidebar accents — we use SVG's built-in patternTransform:
<pattern
id="shah-jahan"
width={100}
height={100}
patternUnits="userSpaceOnUse"
patternTransform={`scale(${tileSize / 100})`}
>
<path d={TILE_PATH} stroke="#2A2418" fill="none" strokeWidth={0.5} />
</pattern>
<rect width="100%" height="100%" fill="url(#shah-jahan)" />
One pre-computed path serves every instance on the site. The browser's SVG renderer handles the scaling — no JavaScript, no recomputation, no hydration needed.
The three patterns
Shah Jahan Mosque, Thatta (1647)
Star polygon: {12/5} — dodecagram (twelve-pointed star, chords skip 5 vertices)
Tiling: Square lattice, tile size 100×100
Path size: 9KB
Character: Dense, intricate. The twelve-fold symmetry creates a rich web of interlocking kites and thin rhombi. When viewed at a distance, the pattern reads as a unified field; up close, the individual geometric relationships reveal themselves.
Used for: Homepage hero background (masked, tiled 9×6 at 220px), section dividers (100px), decorative borders.
This pattern comes from a mosque often called the most beautiful in Pakistan — the blue-and-white tile work of Shah Jahan's Thatta mosque, built for the Mughal emperor's father's memory. Its geometric programme is one of the most complex in Mughal architecture.
Ibn Tulun Mosque, Cairo (879 CE)
Star polygon: {6/2} — hexagram (six-pointed star, chords skip 2 vertices)
Tiling: Hexagonal lattice, tile dimensions 100×173.205 (hexagon aspect ratio √3)
Path size: 1.5KB
Character: Open, meditative. The six-fold symmetry produces larger negative spaces than the twelve-fold Shah Jahan. The pattern breathes. It's appropriate for pages with dense text — the geometry recedes rather than competing with content.
Used for: The Reconstruction section pages, where Iqbal's text is the primary content and the pattern serves as subtle architectural framing.
Ibn Tulun is one of the oldest intact mosques in Cairo, built by Ahmad ibn Tulun during the Abbasid period. Its geometric decoration represents an earlier, more austere aesthetic than the later Mamluk and Ottoman elaborations.
Great Mosque of Córdoba (784 CE)
Star polygon: {8/3} — octagram (eight-pointed star, chords skip 3 vertices)
Tiling: Square lattice
Path size: ~3KB
Character: Balanced between the density of the Shah Jahan and the openness of the Ibn Tulun. The eight-fold symmetry produces the classic "Islamic star" recognisable across the tradition.
Used for: Supplementary pages and custom layouts.
The Córdoba pattern is the only one that still uses client-side computation — a legacy of its original implementation for layouts where exact tile-size flexibility was needed. It's a candidate for pre-computation in a future optimisation pass.
The rendering pipeline
Each pattern follows the same rendering pipeline:
Pre-computed path → SVG <pattern> element → patternTransform for scaling
→ <rect fill="url(#pattern-id)"> for tiling
→ CSS/SVG masking for shaped regions
On the homepage, the Shah Jahan pattern is masked to create the large hero background. The mask uses a gradient fade so the pattern dissolves at the edges rather than ending abruptly:
<svg className="absolute inset-0 w-full h-full" aria-hidden="true">
<defs>
<pattern id="hero-pattern" ...>
<path d={TILE_PATH} stroke={strokeColor} fill="none" />
</pattern>
<mask id="hero-mask">
<rect fill="white" width="100%" height="100%" />
{/* Gradient edges */}
</mask>
</defs>
<rect
width="100%" height="100%"
fill="url(#hero-pattern)"
mask="url(#hero-mask)"
opacity={0.15}
/>
</svg>
The entire component is a server component — no "use client", no JavaScript, no hydration. The browser receives static SVG in the HTML and renders it immediately.
Performance impact
| Metric | Before (runtime) | After (pre-computed) |
|---|---|---|
| Client directive | "use client" |
None (server component) |
| JavaScript | ~160 lines of geometry | 0 |
| Computation per page load | ~300 trig operations | 0 |
| Bundle contribution | ~4KB (minified) | 0 |
| Time to first pattern render | After hydration | Immediate (SSR) |
The pre-computed patterns render in the initial HTML response. On a slow connection, the geometric pattern is visible before any JavaScript has loaded — which means the site's visual identity is present from the first paint.
What we learned
Islamic geometric construction is inherently pre-computable. The patterns are defined by exact mathematical relationships — star polygon notation, tiling symmetry, intersection geometry. There is no randomness, no user input, no state. This makes them ideal candidates for build-time computation. We could have gone further and generated the SVG at build time with a script rather than embedding the path as a constant, but the constant approach is simpler and the 9KB path compresses well.
SVG patterns are remarkably efficient. A single <pattern> element with a 9KB path, tiled across a full-screen region, renders faster than a background image of comparable visual complexity. The browser's SVG rasteriser is optimised for exactly this kind of repetitive geometry. And because it's vector, it's sharp at every screen density — no need for 2x/3x image variants.
The construction method matters culturally. We could have traced the patterns from photographs and saved them as SVG paths directly. Instead, we implemented the classical construction — star polygon chords, intersection computation, tile clipping — because the construction method is itself part of the tradition. The code documents how Islamic artisans actually built these patterns: start with a compass, draw the star, extend the chords, find the intersections. The fact that the computation now runs once at build time rather than by hand on a wall doesn't change the method.
The unfinished work
The Córdoba pattern still computes at runtime. The construction is more complex — it uses ray-exit calculations and pairwise intersection finding rather than simple chord clipping — and we haven't yet extracted a clean pre-computed path. This is straightforward work; we just haven't done it yet.
We've also considered generating patterns dynamically for user-created content — allowing contributors to choose a pattern and colour scheme for their articles, with the tessellation generated at build time from the star polygon notation. The mathematical framework supports this: any {n/k} star polygon on any lattice type produces a valid tessellation. The editorial question is whether this kind of customisation serves the project or distracts from it.
The connection
There is something fitting about rendering Islamic geometric patterns in SVG. The patterns were always a technology for producing infinite complexity from finite rules — a small set of geometric operations, applied recursively, generating a field that extends without boundary. SVG's <pattern> element does exactly the same thing: define a tile, repeat infinitely.
The craftsmen who built the Shah Jahan Mosque in 1647 and the artisans who decorated Ibn Tulun's walls in 879 CE were solving the same problem we're solving: how to fill a surface with mathematical beauty using the most efficient means available. Their tools were compass and straightedge. Ours are trigonometric functions and SVG path data. The geometry is identical.
Built with compass. Rendered with code.