Damascus Chant

A frontend engineering case study for an RTL Arabic archive with SSR, route-level SEO, a performant Leaflet map, and a searchable database of over 5,700 activities

Damascus Chant

Tech stack

  • TypeScript
  • React
  • TanStack Start
  • Vite
  • Tailwind CSS
  • Sanity CMS
  • Cloudflare Workers
  • Leaflet

Damascus Chant is an SSR-first RTL Arabic archive documenting the revolutionary movement in Damascus, Syria. It combines a Sanity-backed content model, route-level SEO, full-text search, timeline navigation, and a Leaflet map with 5,700+ geolocated activities.

The frontend challenge was building a content-heavy Arabic experience that could be indexed, loaded quickly, and still support a highly interactive browser-only map.

My Role

I owned the frontend architecture, content modeling, data import pipeline, performance work, and Cloudflare deployment. The work covered both the public archive and the editorial workflow needed to keep archival content maintainable over time.

The Problem

Documenting non-violent revolutionary activities in Damascus created several frontend and platform challenges:

  • Scale: 5,713 activities across 19 districts, each with dates, locations, organizers, categories, images, and videos
  • Map performance: Thousands of DOM-backed Leaflet markers can block the main thread and make zooming or panning feel heavy
  • Arabic SEO: Activity, martyr, organizer, and district pages needed crawlable SSR HTML with Arabic metadata
  • RTL interface design: Every layout, control, map overlay, and interaction needed to work naturally in Arabic
  • CMS flexibility: Sensitive archival content needed a structured editing workflow that could evolve without redeploying the frontend
  • Edge delivery: The site needed fast delivery for audiences in and around the Middle East

The Solution

Damascus Chant uses a decoupled architecture: Sanity CMS for structured content, TanStack Start for the React frontend, and Cloudflare Workers for edge deployment.

Frontend Architecture

  • SSR-first routing: Content pages render through TanStack Start server loaders so the archive is crawlable before JavaScript loads.
  • Route-level metadata: Each major route uses the head() API for Arabic titles, descriptions, canonical URLs, and social metadata.
  • Client-only map boundary: The main map is isolated from SSR because Leaflet depends on window and document.
  • Lazy map bundle: Leaflet and map-specific code load only on map routes or detail pages that need mini-maps.
  • Structured content layer: Sanity models activities, organizers, categories, districts, neighborhoods, landmarks, and martyrs as typed content relationships.
  • Edge deployment: Cloudflare Workers and CDN caching keep static assets, fonts, and generated pages close to users.

Key Engineering Challenges

1. Rendering 5,700+ Map Points

Challenge: Creating thousands of Leaflet markers at once can overwhelm the browser with DOM nodes, event listeners, layout work, and paint cost.

Solution:

  • Used leaflet.markercluster to group dense activity areas at lower zoom levels
  • Deferred non-critical map enhancements with requestIdleCallback
  • Reduced map query payloads by removing unused GROQ projections
  • Applied zoom-aware CSS classes to adjust marker and district-label visibility
  • Loaded Leaflet only when the map UI is actually mounted

2. SSR and Browser-only Libraries

Challenge: Leaflet assumes browser APIs exist, which conflicts with server rendering.

Solution:

The site uses SSR for content-heavy routes, then draws a clear boundary around browser-only map interactions. The main map route runs as a client route, while smaller detail-page maps are loaded with React.lazy() and Suspense so they do not affect the initial server-rendered page.

This keeps the archive indexable while avoiding brittle typeof window checks scattered across the app.

3. RTL Arabic UX

Challenge: Arabic support is more than setting dir="rtl". Navigation, filters, map controls, typography, timelines, and metadata all need to feel native in Arabic.

Solution:

  • Built layouts with RTL in mind instead of mirroring an LTR design at the end
  • Used Arabic-first typography and spacing decisions for dense archival text
  • Adjusted Leaflet controls and overlays so map interactions matched the page direction
  • Preserved Latin numerals where they improved scanning of dates and counts
  • Tested mixed Arabic and Latin content in titles, metadata, links, and filters

4. Arabic Font Loading

Challenge: Arabic web fonts are large, and loading them from Google Fonts added 300-500ms to Largest Contentful Paint.

Solution:

  • Self-hosted WOFF2 font files
  • Subsetted fonts to Arabic and Latin numeral ranges
  • Used unicode-range to avoid unnecessary glyph downloads
  • Added font-display: swap/optional to prevent invisible text
  • Preloaded critical font files from the document head

5. Hero Video Performance

Challenge: The homepage hero uses an autoplaying background video, which can compete with critical rendering work and hurt LCP.

Solution:

  • Set preload="none" so the video does not compete with critical assets
  • Marked the video as decorative with tabIndex={-1} and aria-hidden
  • Used a real overlay element instead of pseudo-elements for simpler painting
  • Honored prefers-reduced-motion for motion-sensitive users

6. Data Import and Content Modeling

Challenge: Thousands of CSV rows needed to become structured Sanity documents with normalized dates, references, categories, and geolocation.

Solution:

Custom Node.js scripts transformed CSV rows into NDJSON, resolved document references, split multi-value fields, normalized dates, and generated readable IDs so imports could be rerun idempotently.

Performance Work

AreaTechniqueFrontend Impact
Map renderingMarker clustering and lazy Leaflet loadingReduces main-thread and initial bundle cost
Map dataRemoved unused GROQ fieldsSends less JSON to the browser
FontsLocal WOFF2, unicode-range, preload, font-displayImproves Arabic text rendering and LCP
Hero videopreload="none" and decorative accessibility attributesKeeps media from competing with critical render work
Animationprefers-reduced-motion and targeted will-changeReduces paint cost and respects user preferences
CachingCloudflare _headers for fonts and static assetsImproves repeat visits
SEOSSR pages, dynamic sitemap, per-route metadataImproves crawlability of Arabic archive pages

Tradeoffs

  • Leaflet over heavier map platforms: Leaflet kept the map stack lightweight and customizable, but required more manual work for clustering, RTL control placement, and SSR boundaries.
  • Client-only map over full SSR: The map itself cannot be server-rendered safely, so the app keeps surrounding content SSR-friendly and isolates the interactive map where browser APIs are required.
  • Sanity over static JSON: Sanity added CMS complexity, but made the archive maintainable for editors and avoided hardcoding sensitive historical records into the frontend.
  • Self-hosted fonts over Google Fonts: Self-hosting required more asset work, but removed a third-party request from the critical rendering path and made Arabic font loading more predictable.

Outcome

Damascus Chant is live at damascuschant.com as a searchable Arabic historical archive.

  • 5,713 archived activities across 19 districts
  • 113 revolutionary entities catalogued
  • Full-text search across activities, martyrs, and organizers
  • Interactive map with clustering and filtering
  • Timeline navigation for historical exploration
  • Dynamic sitemap for search engine indexing
  • SSR-first Arabic pages with client-only map boundaries
  • Fully RTL interface
  • Google PageSpeed mobile score of 90, with accessibility, best practices, and SEO at 100