An open-source, ultra-performant architectural walking guide and interactive 3D tour for the Historic Downtown of San Salvador, El Salvador. Built with Astro 7, Tailwind CSS v4, Preact, Three.js, and Leaflet, crafted in an authentic 1920s Bauhaus Constructivist aesthetic.
SVX is a cultural preservation and urban exploration platform dedicated to the rich architectural heritage of downtown San Salvador. From the majestic Neo-Renaissance Palacio Nacional to the brutalist stained-glass sanctuary of Iglesia El Rosario, SVX provides citizens, tourists, and architecture lovers with an educational walking itinerary, detailed monument histories, local gastronomy stops, and interactive 2D/3D map navigation.
The site is designed as a living 1920s Bauhaus Exhibition Poster: celebrating geometric purity, primary color blocking, structural framing, and physical mechanical interactions while respecting strict web performance budgets.
- π¨ Bauhaus Constructivist Design System:
- Saturated pure primary colors: Bauhaus Red (
#D02020), Ultramarine Blue (#1040C0), and Cadmium Yellow (#F0C020). - Heavy architectural framing with stark black borders (2px mobile, 4px desktop).
- Tactile physical interactions: zero-blur offset drop shadows (
4px/8px) that depress mechanically on press (active:translate-x-[2px]). - Monochromatic heritage photography that bursts into rich full color on hover.
- Saturated pure primary colors: Bauhaus Red (
- π Full Bilingual Support (Spanish & English):
- Spanish by default on first visit with persistent selection stored in
localStorage(svx_language). - Instantaneous client-side switching: toggling between
ESandENupdates all interface text, historical narratives, titles, badges, and metadata without page reloads. - Constructivist UI toggle: accessible
ES | ENbutton group in the site header with clear active states, keyboard focus, and mobile drawer support. - Island integration: interactive Preact islands (filter directory, 3D tour viewer HUD, 2D Leaflet popups) subscribe reactively to language changes via custom events (
svx:lang). - Cultural & historical fidelity: proper official monument and building names are strictly preserved, accompanied by natural, contextually accurate historical English translations.
- Spanish by default on first visit with persistent selection stored in
- πΉοΈ Interactive 3D Isometric Tour Experience:
- Custom Three.js isometric engine rendering procedural 3D architectural models of historic monuments.
- Interactive waypoint navigation: click steps to fly the orbital camera through the route.
- Seamless toggle between a high-energy 3D Isometric View and a functional 2D Leaflet Map.
- Smooth animation loops with requestAnimationFrame and WebGL context lifecycle management.
- β‘ 0 KB Client JavaScript Budget on Static Pages:
- All content pages (
/,/monumentos/[slug]/,/tours/,/gastronomia/,/404) ship zero executable client JavaScript. - Interactive Preact islands are strictly isolated to
/monumentos/(directory filtering) and/tours/ruta-del-corazon-historico/(map/3D switcher).
- All content pages (
- π Persistent Dark & Light Mode:
- Tactile constructivist toggle button with zero layout flash (FOUC) powered by a lightweight synchronous inline bootstrap script.
- Full local storage synchronization across tabs and window resize events.
- π Comprehensive SEO & Structured Data (JSON-LD):
- Rich Schema.org data for Google SERP rich snippets:
BreadcrumbListon all directory and detail pages.LandmarksOrHistoricalBuildings+TouristAttractionon monument detail pages.TouristTrip+ItemListitinerary on tour routes.Restaurantlistings for local gastronomy.CollectionPageschemas for directory catalogs.Organization&WebSiteschemas on the root route.
- Automated
robots.txtand XML sitemaps (sitemap-index.xml). - Responsive OpenGraph & Twitter Cards (
og-default.png) rendered as authentic Bauhaus posters.
- Rich Schema.org data for Google SERP rich snippets:
- π± PWA Ready & Multi-Platform Icons:
- High-contrast SVG favicon visible on both dark and light browser chrome.
- Multi-resolution
favicon.ico(16px, 32px, 48px), Apple Touch Icon (180x180), Android PWA icons (192x192, 512x512), andsite.webmanifest.
- βΏ Built-in Accessibility (WCAG 2.1 AA):
- 100% of text/background color pairs clear the 4.5:1 AA contrast threshold in both light and dark modes.
- Keyboard accessible: visible focus rings (
:focus-visible), skip-to-content links, and semantic landmark roles.
| Component | Technology | Description |
|---|---|---|
| Framework | Astro 7 | Static site generator (output: 'static') with TypeScript strict mode |
| UI Islands | Preact 10 | Lightweight 3KB reactive islands for client interactivity |
| 3D Graphics | Three.js | Procedural isometric 3D monument rendering and orbital camera transitions |
| 2D Mapping | Leaflet | Interactive OpenStreetMap navigation, lazy-loaded inside the island |
| i18n / Languages | Custom Reactive Dictionary | Full Spanish (default) & English support with anti-flash bootstrap & zero runtime libraries |
| Styling | Tailwind CSS v4 | High-performance CSS-first engine via @tailwindcss/vite |
| Icons | @lucide/astro |
Crisp modern icons for Astro components |
| Content | Astro Content Collections | Type-safe Markdown and YAML schemas validated with Zod |
| Fonts | Self-hosted Fonts | Variable Inter + DM Serif Display bundled locally (no third-party requests) |
| Quality Gate | Node.js Test Runner | Automated mechanical audit verifying contrast, JS budget, and HTML semantics |
| Hosting | Cloudflare Workers | Distributed edge static hosting |
- Node.js
>= 22.12.0 - npm
>= 9.6.5
Clone the repository and install dependencies:
git clone https://github.com/KevinArce/SVX.git
cd SVX
npm install| Command | Action |
|---|---|
npm run dev |
Starts local development server at http://localhost:4321 |
npm run build |
Runs type checks (astro check) and generates static output in dist/ |
npm run preview |
Previews the production static build locally |
npm run audit |
Runs the mechanical quality checklist (scripts/audit.mjs) |
npm run favicons |
Generates SVG, ICO, Apple Touch, and PWA icon derivatives |
npm run og-images |
Rasterizes vector SVG social banners into 1200x630 PNG share cards |
npm run placeholders |
Regenerates vector placeholder artwork for content entries |
Every build must compile cleanly and pass the project's automated mechanical audit:
npm run build && npm run auditThe audit script (scripts/audit.mjs) verifies:
- JavaScript Budget: Only island routes (
/monumentos/and/tours/ruta-del-corazon-historico/) emit client-side scripts. - Leaflet & Three.js Isolation: No heavy libraries leak into the global
<head>. - Image Dimensions & Semantics: Every
<img>carries explicit dimensions (or aspect ratio) and accessiblealttext. - Document Structure: Exactly one
<h1>, one<main id="contenido">, labelled navigation, and.skip-linkfirst in tab order. - Stylesheet Guarantees:
:focus-visible,prefers-reduced-motion, dark mode token overrides, and CSS cross-document@view-transition. - Color Contrast: 18 foreground/background combinations verified to meet or exceed WCAG 2.1 AA (4.5:1) in both light and dark themes.
- Source Hygiene: 0
console.logcalls and 0 commented-out code in shipped files.
SVX/
βββ public/ # Static assets published at root
β βββ favicon.svg # Bauhaus vector favicon
β βββ favicon.ico # Multi-size ICO fallback
β βββ apple-touch-icon.png # 180x180 Apple touch icon
β βββ icon-192.png, icon-512 # Android / PWA app icons
β βββ og-default.png # 1200x630 Bauhaus social share card
β βββ robots.txt # Search engine crawler directives
β βββ site.webmanifest # Progressive Web App manifest
βββ scripts/ # Automation and audit tooling
β βββ audit.mjs # Mechanical quality audit gate
β βββ generate-favicons.mjs # Headless icon rasterizer
β βββ generate-og-images.mjs # DevTools protocol OG renderer
β βββ generate-placeholders # Procedural SVG vector art generator
βββ src/
β βββ assets/ # Fonts, vector sources, and default images
β βββ components/ # Reusable zero-JS .astro components
β β βββ islands/ # Client-hydrated Preact islands (Map, 3D, Filter)
β β βββ SiteHeader.astro # Navigation and dark/light toggle
β β βββ SiteFooter.astro # Bauhaus constructivist footer
β βββ content/ # Content collections (Markdown + schemas)
β β βββ monuments/ # Historical landmark entries
β β βββ restaurants/ # Dining and pupuserΓa listings
β β βββ tours/ # Guided walking tour itineraries
β βββ layouts/ # BaseLayout.astro: head, SEO, schemas, fonts
β βββ lib/ # Site constants, Schema.org JSON-LD builders, and i18n
β β βββ i18n/ # Bilingual translations (translations.ts, index.ts)
β β β βββ index.ts # Helper utilities, types, and persistence hooks
β β β βββ translations.ts # Full ES/EN dictionary (UI, monuments, tours, restaurants)
β βββ styles/
β βββ global.css # Tailwind CSS v4 @theme design tokens
βββ astro.config.ts # Astro configuration and self-hosted fonts
βββ package.json
βββ tsconfig.json
We welcome contributions from historians, developers, designers, and locals passionate about Salvadoran culture!
Create a new Markdown file under src/content/monuments/[slug].md:
---
title: "Palacio Nacional de El Salvador"
shortDescription: "Sede histΓ³rica del gobierno salvadoreΓ±o en el corazΓ³n del centro."
architecturalStyle: "NeoclΓ‘sico / Renacentista"
yearBuilt: 1911
zone: "Plaza Barrios"
coordinates:
lat: 13.6989
lng: -89.1914
visitingHours: "MarβDom: 9:00β16:00"
admission: "Gratis"
featured: true
heroImage: "./palacio-nacional.svg" # Replace with real .jpg/.webp when photography is ready
heroImageAlt: "Fachada principal del Palacio Nacional"
timeline:
- year: 1866
event: "ConstrucciΓ³n del palacio original de madera."
- year: 1889
event: "Incendio destruye la estructura primitiva."
- year: 1911
event: "InauguraciΓ³n del actual palacio neoclΓ‘sico."
nearbyRestaurantSlugs:
- pupuseria-del-centro
---
Your well-researched historical article goes here in Spanish (es-SV)...Create a new tour entry under src/content/tours/[slug].md:
---
title: "Ruta de los Teatros y Plazas"
subtitle: "Recorrido por la arquitectura escΓ©nica y las plazas fundacionales."
distanceKm: 1.8
durationMinutes: 45
difficulty: "FΓ‘cil"
bestTimeOfDay: "MaΓ±ana (8:00β10:00)"
coverImage: "./ruta-teatros.svg"
coverImageAlt: "Mapa del recorrido cultural"
waypoints:
- order: 1
monumentSlug: "teatro-nacional"
walkingTip: "Cruza por el paso peatonal seΓ±alizado sobre la Calle Delgado."
estimatedMinutes: 10
---
Tour description and tips...SVX provides comprehensive bilingual support (Spanish and English). When introducing new monuments, routes, restaurants, or UI components:
- Open
src/lib/i18n/translations.ts. - Add corresponding entries under both
esandendictionaries:ui: General UI labels, buttons, badges, filter labels, and alert messages.monuments: Short description, architectural style, visiting hours, admission, timeline events, and full historical prose (contentHtml).tours: Subtitle, difficulty, best time, waypoint tips, and itinerary content.restaurants: Cuisine, zone, must-try recommendations, and opening hours.
- Keep official proper names untouched (e.g. Palacio Nacional, Iglesia El Rosario, Plaza Gerardo Barrios).
- Use standard data attributes in
.astrotemplates:data-i18n="key": Injects translatedtextContent.data-i18n-html="key": Injects translatedinnerHTMLfor formatted historical articles.data-i18n-attr="attr:key": Dynamically updates element attributes (e.g.aria-label:nav.aria,title:theme.toggle).
- Fork the repository and create your feature branch:
git checkout -b feat/new-monument-entry
- Make your additions or corrections.
- Validate strict typing and mechanical audit rules:
npm run build && npm run audit - Commit using Conventional Commits:
git commit -m "feat(content): add Iglesia San Esteban historical entry" - Push to your branch and open a Pull Request.
SVX is deployed on Cloudflare Workers (with static assets) at https://svx.kevinarce.workers.dev/:
- Build command:
npm run build - Output directory:
dist - Node version:
>=22.12.0
No complex server adapter is required: output: 'static' emits plain HTML, CSS, SVG, and client bundles that Cloudflare serves with global edge caching and instant page loads.
Crafted with dedication by Kevin Arce:
- π Website: arcelabs.com
- π GitHub: @KevinArce
- β Support the Project: If you appreciate this work and want to support further development, buy me a coffee!
This project is licensed under the MIT License Β© 2026 Kevin Arce. Feel free to use, adapt, and build upon this project for educational, cultural, or commercial purposes.