MASTER PROMPT — Landing SEO Local de Servicios Automotrices a Domicilio
Documento maestro generado a partir de una sesión real de iteración. Pégalo completo en un nuevo chat para que la IA reproduzca el mismo nivel de calidad, arquitectura y aprendizajes. Sustituye los placeholders entre
{{LLAVES}}por los valores del cliente real.
1. ROL Y OBJETIVO
Actúa como Desarrollador Web Full Stack Senior + Especialista en SEO Técnico/Local, experto en Astro, Tailwind CSS, Git/GitHub y Cloudflare Pages.
Objetivo: Construir una landing page de servicios a domicilio, lista para producción, optimizada para:
- Conversión móvil
- Core Web Vitals (95+ en PageSpeed mobile)
- SEO Local / Geo-SEO (city-level landing pages)
- Rich snippets via Schema.org JSON-LD
Nicho del ejemplo: Recarga de Gas Aire Acondicionado Automotriz a Domicilio en Santiago de Chile (Región Metropolitana). El patrón es replicable a cualquier nicho de servicios locales: plomería, electricista, cerrajero, limpieza, etc.
2. STACK TÉCNICO OBLIGATORIO
| Capa | Tecnología | Razón |
|---|---|---|
| Framework | Astro 4.x (SSG / static output) | HTML estático = máxima velocidad |
| Estilos | Tailwind CSS 3.x con tokens custom | Design system consistente |
| Interactividad | Vanilla JS en <script> (sin React/Vue) |
Mínimo JS = mejor INP |
| Mapas | Leaflet 1.9.4 + tiles OpenStreetMap con filtro CSS | Ver sección 11 — NO usar SVG custom ni CartoDB |
| Imágenes | Sharp (Node) para optimizar a WebP + JPG | ~50% de ahorro de peso |
| Hosting | Cloudflare Pages | CDN global gratis |
| Control versiones | Git + GitHub | Deploy automático |
Prohibido: React, Vue, Svelte, jQuery, Bootstrap, frameworks CSS pesados, animaciones GSAP, Lottie.
3. SISTEMA DE DISEÑO — TOKENS TAILWIND EXACTOS
Configurar en tailwind.config.mjs:
colors: {
'primary-cyan': '#00BCD4',
'primary-teal': '#00838F',
'accent-orange': '#ff6b00',
'accent-orange-light':'#ff8c33',
'dark-navy': '#0b1020',
'dark-navy-alt': '#121a33',
'ink-dark': '#1a1a1a',
'text-muted': '#5b6475',
'border-light': '#e6e9f0',
'bg-alt': '#f5f7fb',
'whatsapp-green': '#25D366',
},
fontFamily: { sans: ['Poppins', 'ui-sans-serif', 'system-ui', 'sans-serif'] }
Fuente: Poppins (pesos 400–900) cargada desde Google Fonts con preconnect + display=swap.
Animaciones custom útiles:
pulse-slow(badge pulsante)float(tarjeta glassmorphism)glow-pulse(halo detrás de cards)fade-up(reveal on scroll)
4. ARQUITECTURA DE CARPETAS
proyecto/
├── astro.config.mjs # SSG, site URL, @astrojs/tailwind
├── tailwind.config.mjs # Tokens + animaciones
├── tsconfig.json # Path aliases @components, @layouts
├── package.json
├── public/
│ ├── favicon.svg
│ ├── robots.txt # Con Sitemap: https://dominio.cl/sitemap.xml
│ ├── manifest.webmanifest # PWA
│ └── images/
│ ├── logo.svg
│ ├── og/ # Open Graph 1200×630 (JPG preferible)
│ ├── icons/ # icon-192.png, icon-512.png, apple-touch-icon.png
│ ├── gallery/ # Fotos renombradas con keywords SEO
│ └── services/ # Fotos por servicio
└── src/
├── data/
│ └── comunas.ts # Data centralizada de ubicaciones (slug, nombre, zona, lat/lng, FAQ propio)
├── layouts/
│ └── Layout.astro # Head + SEO + Geo-tags + Schema JSON-LD + manifest link
├── components/
│ ├── Navbar.astro
│ ├── Hero.astro
│ ├── TrustBar.astro
│ ├── ServicesGrid.astro
│ ├── ProcessSteps.astro
│ ├── PricingSection.astro
│ ├── CoverageMap.astro # Buscador de comunas con chips
│ ├── LeafletMap.astro # Mapa interactivo (ver sección 11)
│ ├── Gallery.astro # Lightbox accesible
│ ├── FaqSection.astro
│ ├── FloatingActions.astro # WhatsApp flotante + barra móvil
│ └── Footer.astro
└── pages/
├── index.astro # Home
├── comunas.astro # Hub de todas las ubicaciones + mapa amplio
├── comuna/[comuna].astro # 52 landings dinámicas por ubicación
├── faq.astro # FAQ global con schema FAQPage
├── galeria.astro # Galería completa
├── privacidad.astro # Política ARCO (Ley 19.628 Chile)
├── sitemap.xml.ts # Sitemap dinámico
└── robots.txt.ts # (opcional, o usar public/robots.txt)
5. COMPONENTES — ESPECIFICACIÓN DETALLADA
5.1 Layout.astro — Head + SEO + Schema
<html lang="es-CL">conscroll-smoothyscroll-padding-top: 90px<title>con keyword + intención local<meta name="description">persuasiva con precio + tiempo + cobertura + CTA- Geo-tags:
geo.region=CL-RM,geo.placename=Santiago,geo.position=-33.4372;-70.6506,ICBM - Open Graph:
og:type=website,og:locale=es_CL,og:image1200×630,og:url,og:site_name - Twitter Cards:
summary_large_image <link rel="canonical"><link rel="manifest" href="/manifest.webmanifest"><link rel="apple-touch-icon" sizes="180x180" href="/images/icons/apple-touch-icon.png">- Fonts: preconnect a fonts.googleapis.com y fonts.gstatic.com
- 3 schemas JSON-LD inyectados: AutomotiveBusiness + Service + FAQPage (ver sección 7)
- CSS global: scroll smooth, scrollbar dark theme,
prefers-reduced-motion,:focus-visiblecyan - IntersectionObserver para reveal on scroll (
[data-reveal]→.is-visible)
5.2 Navbar.astro
- Fixed top,
backdrop-blur-md,bg-dark-navy/80, sombra dinámica al scroll - Logo SVG con gradiente cyan/teal
- Links ancla: Inicio, Proceso, Cobertura RM, Comunas (mega-dropdown), Galería, Precios, Preguntas
- Dropdown "Servicios" (hover, 320px width): Recarga Gas R134a, Detección de Fugas UV, Cambio de Filtro, Diagnóstico de Compresor
- Mega-dropdown "Comunas" (hover, 560px width): top 12 comunas en grid 3 columnas + botón naranja "Ver todas" → /comunas
- CTA WhatsApp verde (esquina derecha desktop)
- Menú móvil hamburguesa con acordeón Servicios y Comunas como enlace directo
- JS Vanilla: toggle menú mobile, cerrar con Escape, cerrar al clic en link
5.3 Hero.astro — ⚠️ LECCIÓN CRÍTICA
NO uses la foto como background absoluto del Hero con object-cover. Eso causa:
- Foto con zoom/recortada
- Texto del Hero encima opacando la foto
- Mala legibilidad
Patrón correcto (aprendido en esta sesión):
Hero sin foto de fondo, solo glow decorativo (
bg-hero-radial+ blobs blur)Texto del H1 + subtítulo + botones + stats directamente sobre el fondo oscuro
Foto como
<figure>bloque independiente después del grid de stats:object-contain(noobject-cover) → se ve completa sin recortesmax-h-[70vh]→ no domina toda la pantallabg-dark-navy-altde fallback para cuando la imagen no llena el ancho (vertical)rounded-3xl+border+shadow-2xl+ caption con info del servicio
Sección "Servicio Garantizado" (checklist + precio + estrellas) DEBE ir en su propia sección debajo del Hero, NO como columna derecha del Hero.
5.4 ServicesGrid.astro
- Grid responsive 1/2/4 columnas
- Tarjeta con
rounded-xl-card(18px), barra superior animada en hover con gradientefrom-primary-cyan via-primary-teal to-accent-orange(scale-x-0 group-hover:scale-x-100) - Imagen con
loading="lazy",decoding="async",width+heightexplícitos (evita CLS) - Badge tipo tag en esquina superior izquierda
- Lista de inclusiones con checks
- Precio grande en accent-orange + duración
- CTA "Cotizar" con WhatsApp link
5.5 PricingSection.astro
- 3 planes (Básico, Pack Destacado, Especializado)
- Plan destacado: fondo
dark-navy, borderaccent-orange,lg:scale-105 - Precio gigante en accent-orange (text-5xl/text-6xl)
- Lista de inclusiones (✓ verde) y exclusiones (✗ gris line-through)
- CTA específico por plan con mensaje WhatsApp pre-rellenado
5.6 CoverageMap.astro (buscador de chips)
- Buscador input + grid de chips clickeables (52 comunas RM)
- JS Vanilla: filtra chips en tiempo real + muestra resultado dinámico con CTA
- Resultado: card verde con confirmación + botón "Reservar ahora"
5.7 LeafletMap.astro — ⚠️ VER SECCIÓN 11
- NO SVG custom (lag con 50+ markers animados)
- NO CartoDB tiles (requiere API key → muestra "API KEY REQUIRED")
- SÍ Leaflet 1.9.4 + tiles OpenStreetMap estándar + filtro CSS para dark theme
- Markers
divIconcon dot coloreado por zona - Popup con: nombre, zona, tiempo, descripción, barrios, botón "Ir a la landing"
- Buscador sincronizado mapa↔lista
flyToanimado al hacer click en item de lista
5.8 Gallery.astro
- Variantes:
compact(4 fotos en index/comuna) yfull(todas en /galeria) <picture>con source WebP + fallback JPGloading="lazy",width+height,decoding="async"- Lightbox modal accesible: Escape para cerrar, flechas ←/→ para navegar, click fuera para cerrar
- Caption con info del servicio
5.9 FaqSection.astro
- Acordeón accesible:
aria-expanded,aria-controls, soporte teclado Enter/Space - Solo un panel abierto a la vez (comportamiento acordeón clásico)
- Icono chevron rota 180° al abrir
5.10 FloatingActions.astro
- Botón flotante WhatsApp bottom-right (desktop + mobile)
- Tooltip desktop aparece tras 3s de inactividad
- Barra fija inferior mobile (Call + WhatsApp) —
md:hidden, grid 2 columnas padding-bottom: 72pxen body mobile para que la barra no tape contenido
5.11 Footer.astro
- 4 columnas: marca+contacto, navegación, servicios+legal, datos fiscales
- Bloque SEO: listado de 52 comunas atendidas en formato "comuna1, comuna2, ..." (refuerza Geo-SEO)
- Redes sociales: WhatsApp, Instagram, Facebook
- Bottom bar: copyright + última actualización + status sistema
6. PÁGINA DINÁMICA POR COMUNA — [comuna].astro
Esta es la joya del SEO Local. Generar una landing por cada ubicación atendida.
Data source: src/data/comunas.ts
export interface Comuna {
slug: string; // 'las-condes'
nombre: string; // 'Las Condes'
zona: 'Centro'|'Oriente'|'Norte'|'Sur'|'Suroriente'|'Poniente'|'Surponiente'|'Rural';
descripcion: string; // SEO description única
barrios?: string[];
lat: number;
lng: number;
tiempoRespuesta: string; // '60-90 min'
faqs: ComunaFAQ[]; // 5 FAQs únicas por comuna
}
getStaticPaths()
Generar todas las landings en build time:
export function getStaticPaths() {
return comunas.map((comuna) => ({
params: { comuna: comuna.slug },
props: { comuna },
}));
}
Estructura de la landing por comuna
- Hero específico: H1 con "Recarga de Gas A/C a Domicilio en {comuna.nombre}"
- Breadcrumb: Inicio › Cobertura RM › {comuna.nombre}
- Badge: "Desde $35.000 · Atención hoy en {comuna.nombre}"
- Barrios atendidos como chips
- CTA WhatsApp con mensaje pre-rellenado mencionando la comuna
- TrustBar + ServicesGrid + ProcessSteps + PricingSection (componentes compartidos)
- FAQ específico de la comuna (5 preguntas con nombre de la comuna en cada una)
- Gallery compacta
- Comunas vecinas (de la misma zona) como chips clickeables
Schemas por comuna (4 en total)
AutomotiveBusinessconareaServed= City de la comuna +geocon lat/lng específicosServiceconareaServed= City +Offeren CLPFAQPagecon las 5 FAQs únicas de la comunaBreadcrumbListcon Inicio › Cobertura RM › {comuna}
7. SCHEMA.ORG JSON-LD — PATRONES
7.1 AutomotiveBusiness (en Layout principal)
{
"@context": "https://schema.org",
"@type": ["AutomotiveBusiness", "AutoRepair"],
"@id": "https://dominio.cl/#business",
"name": "GlobalPro Automotriz",
"telephone": "+56987654321",
"image": ".../og-image.jpg",
"logo": ".../logo.svg",
"priceRange": "$$",
"currenciesAccepted": "CLP",
"paymentAccepted": "Efectivo, Transferencia, Transbank",
"address": { "@type": "PostalAddress", "addressLocality": "Santiago", "addressRegion": "RM", "addressCountry": "CL" },
"geo": { "@type": "GeoCoordinates", "latitude": -33.4372, "longitude": -70.6506 },
"areaServed": [ /* array de { "@type": "City", "name": "..." } por cada comuna */ ],
"openingHoursSpecification": [ /* lunes-viernes 08-22, sáb-dom 09-21 */ ],
"aggregateRating": { "@type": "AggregateRating", "ratingValue": "4.9", "reviewCount": "327" }
}
7.2 Service
{
"@context": "https://schema.org",
"@type": "Service",
"serviceType": "Recarga de Gas Aire Acondicionado Automotriz",
"provider": { "@id": ".../#business" },
"areaServed": { "@type": "AdministrativeArea", "name": "Región Metropolitana" },
"offers": { "@type": "Offer", "price": "35000", "priceCurrency": "CLP", "availability": "InStock" }
}
7.3 FAQPage
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{ "@type": "Question", "name": "...", "acceptedAnswer": { "@type": "Answer", "text": "..." } }
]
}
7.4 BreadcrumbList (solo en landings por comuna)
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "Inicio", "item": "https://dominio.cl/" },
{ "@type": "ListItem", "position": 2, "name": "Cobertura RM", "item": ".../#cobertura" },
{ "@type": "ListItem", "position": 3, "name": "Las Condes", "item": ".../comuna/las-condes" }
]
}
8. SEO ON-PAGE CHECKLIST
- Un único
<h1>semántico con keyword transaccional - Jerarquía estricta:
<h2>por sección,<h3>para items dentro de sección -
<title>50–60 chars con keyword + ubicación -
<meta description>150–160 chars con precio + tiempo + CTA - Geo-tags:
geo.region,geo.placename,geo.position,ICBM - Open Graph completo con
og:locale=es_CL - Twitter Cards
summary_large_image -
<link rel="canonical"> -
lang="es-CL"en<html> -
robots.txtconSitemap: https://dominio.cl/sitemap.xml -
sitemap.xmldinámico con todas las URLs (home + comunas + faq + galeria + privacidad) - Imágenes:
altdescriptivo con keywords,width+heightexplícitos,loading="lazy"(excepto hero confetchpriority="high") -
prefers-reduced-motionrespetado -
:focus-visibleaccesible (outline cyan)
9. PWA — WEB MANIFEST
public/manifest.webmanifest:
{
"name": "GlobalPro Automotriz - Recarga de Gas A/C a Domicilio",
"short_name": "GlobalPro",
"description": "...",
"start_url": "/",
"display": "standalone",
"background_color": "#0b1020",
"theme_color": "#00838F",
"lang": "es-CL",
"icons": [
{ "src": "/favicon.svg", "sizes": "any", "type": "image/svg+xml", "purpose": "any maskable" },
{ "src": "/images/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
{ "src": "/images/icons/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" }
],
"shortcuts": [
{ "name": "Reservar", "url": "/?utm_source=pwa#inicio" },
{ "name": "Precios", "url": "/?utm_source=pwa#precios" },
{ "name": "Cobertura", "url": "/?utm_source=pwa#cobertura" }
]
}
Generar iconos PNG con sharp desde el favicon.svg:
await sharp(svgBuffer, { density: 384 }).resize(192, 192).png().toFile('icon-192.png');
await sharp(svgBuffer, { density: 384 }).resize(512, 512).png().toFile('icon-512.png');
await sharp(svgBuffer, { density: 384 }).resize(180, 180).png().toFile('apple-touch-icon.png');
10. IMÁGENES — CONVENCIONES
Renombrado SEO
Nombres de archivo en kebab-case con keywords del nicho, separados por guiones:
- ✅
recarga-gas-aire-acondicionado-automotriz-domicilio-santiago-1.jpg - ✅
tecnico-recarga-gas-r134a-auto-domicilio-rm-3.webp - ❌
IMG-20260929-WA0132.jpg
Optimización
Script Node usando sharp:
await sharp(input).resize({ width: 1200, height: 1200, fit: 'inside', withoutEnlargement: true })
.jpeg({ quality: 78, progressive: true, mozjpeg: true }).toBuffer();
await sharp(input).resize({...}).webp({ quality: 75 }).toFile(output);
Uso en HTML
<picture>
<source srcset="/images/gallery/foto.webp" type="image/webp" />
<img src="/images/gallery/foto.jpg" alt="keyword + ubicación + marca"
width="900" height="1200" loading="lazy" decoding="async" />
</picture>
Excepción: Hero principal usa fetchpriority="high" (no lazy).
11. MAPA INTERACTIVO — LECCIONES CRÍTICAS
❌ NO USES SVG CUSTOM
SVG con 50+ markers animados + transforms JS manuales para zoom/pan = lag severo en mobile y baja gama. El re-render constante del SVG mata el performance.
❌ NO USES CARTODB TILES
https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png ahora requiere API key registrada en carto.com/basemaps/apikey. Sin key muestra watermark "API KEY REQUIRED" tapando el mapa.
✅ SOLUCIÓN: Leaflet + OpenStreetMap + Filtro CSS
// Tiles OSM estándar (gratis, sin API key, sin límites duros)
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OpenStreetMap',
subdomains: 'abc',
maxZoom: 19,
className: 'osm-dark-tiles', // clave para tema oscuro
}).addTo(map);
/* Invertir y teñir tiles OSM para combinar con dark-navy */
.osm-dark-tiles {
filter: invert(1) hue-rotate(180deg) brightness(0.85) contrast(0.9) saturate(0.7);
}
Carga vía CDN con SRI
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin="" />
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""></script>
Configuración del mapa
const map = L.map('leaflet-map', {
center: [-33.45, -70.65],
zoom: 10, // 10 para vista RM completa, 11 para más cercana
minZoom: 9,
maxZoom: 16,
zoomControl: true,
scrollWheelZoom: true,
});
Marker custom con divIcon
const makeIcon = (color) => L.divIcon({
className: 'comuna-marker-leaflet',
html: `<div class="dot" style="background:${color};"></div>`,
iconSize: [16, 16],
iconAnchor: [8, 8],
popupAnchor: [0, -10],
});
Popup con CTA
Cada marker tiene un popup con: nombre, zona, tiempo, descripción, stats, barrios (chips), y botón "Ir a la landing de {comuna}" que linkea a /comuna/[slug].
12. SITEMAP DINÁMICO
src/pages/sitemap.xml.ts:
import type { APIRoute } from 'astro';
import { comunas } from '../data/comunas.ts';
const SITE_URL = 'https://dominio.cl';
export const GET: APIRoute = () => {
const pages = [
{ url: '/', priority: '1.0', changefreq: 'weekly' },
{ url: '/faq', priority: '0.8', changefreq: 'monthly' },
{ url: '/galeria', priority: '0.7', changefreq: 'monthly' },
{ url: '/comunas', priority: '0.9', changefreq: 'monthly' },
{ url: '/privacidad', priority: '0.3', changefreq: 'yearly' },
...comunas.map(c => ({
url: `/comuna/${c.slug}`,
priority: '0.9',
changefreq: 'monthly',
})),
];
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${pages.map(p => ` <url>
<loc>${SITE_URL}${p.url}</loc>
<lastmod>${new Date().toISOString().split('T')[0]}</lastmod>
<changefreq>${p.changefreq}</changefreq>
<priority>${p.priority}</priority>
</url>`).join('\n')}
</urlset>`;
return new Response(xml, { headers: { 'Content-Type': 'application/xml; charset=utf-8' } });
};
13. WORKFLOW DE DESPLIEGUE
13.1 Inicializar Git local
cd proyecto
git init -b main
git add .
git commit -m "feat: landing inicial - [descripción]"
13.2 Crear repo en GitHub
Opción A — GitHub CLI (recomendado):
gh auth login
gh repo create nombre-repo --private --source=. --push
Opción B — API REST con token:
curl -X POST https://api.github.com/user/repos \
-H "Authorization: Bearer $GH_TOKEN" \
-d '{"name":"nombre-repo","private":true}'
git remote add origin https://x-access-token:$GH_TOKEN@github.com/USER/nombre-repo.git
git push -u origin main
# Limpiar token del remote después:
git remote set-url origin https://github.com/USER/nombre-repo.git
13.3 Deploy en Cloudflare Pages
Opción A — Conectar GitHub en dashboard (recomendado):
- dash.cloudflare.com → Workers & Pages → Create → Pages → Connect to Git
- Seleccionar repo
- Config:
- Framework preset:
Astro - Build command:
npm run build - Build output directory:
dist
- Framework preset:
- Save and Deploy
Opción B — Wrangler CLI:
npm install -g wrangler
wrangler login
wrangler pages project create nombre-proyecto
npm run build
wrangler pages deploy dist --project-name=nombre-proyecto --branch=main
Opción C — Wrangler con API token (para automatizar):
export CLOUDFLARE_API_TOKEN="cfat_..."
export CLOUDFLARE_ACCOUNT_ID="..."
npx wrangler pages deploy dist --project-name=nombre-proyecto --branch=main
13.4 Configurar dominio custom
- Cloudflare Pages → tu proyecto → Custom domains → Set up a custom domain
- Agregar registro CNAME:
Type: CNAME | Name: @ | Value: nombre-proyecto.pages.dev - SSL se emite automáticamente
14. SEGURIDAD — REGLAS CRÍTICAS
⚠️ NUNCA compartas tokens en chat
Si el usuario pega tokens de GitHub (ghp_...) o Cloudflare (cfat_...) en el chat:
- Advertir inmediatamente que los revoque
- No usar los tokens sin confirmación explícita del usuario
- Recomendar rotación inmediata en:
Si el usuario autoriza usar los tokens
- Verificar scopes del token de GitHub (
repo,admin:orgsi necesario) - Verificar que el token de Cloudflare tiene permisos de Pages
- NUNCA commitear tokens al repo (verificar
.gitignore) - Después del push, limpiar el remote URL:
git remote set-url origin https://github.com/USER/repo.git - Recordar al usuario revocar los tokens al finalizar
.gitignore obligatorio
node_modules/
dist/
.env
.env.local
.env.production
.astro/
.DS_Store
15. CALIDAD — CHECKLIST FINAL
Antes de declarar "listo", verificar:
Build
-
npm run buildcompila sin errores ni warnings - Total de páginas generadas = 1 home + N landings por comuna + páginas auxiliares
- Tamaño del dist razonable (<10MB sin imágenes grandes)
SEO
- Un único
<h1>por página - Schemas JSON-LD válidos (probar en https://search.google.com/test/rich-results)
- Sitemap accessible en
/sitemap.xml - robots.txt con link al sitemap
- Open Graph image 1200×630
- Geo-tags presentes
- canonical URL correcta
Performance
- Sin React/Vue/jQuery
- Imágenes en WebP + JPG con
<picture> -
loading="lazy"en todas las imágenes bajo el fold -
fetchpriority="high"en imagen del Hero -
width+heighten todas las imágenes (evita CLS) - Fuentes con
preconnect+display=swap - CSS crítico inline en
<head>
Accesibilidad
-
lang="es-CL"en<html> -
:focus-visiblecon outline cyan -
aria-labelen botones de iconos -
aria-expandeden dropdowns y acordeones - Soporte teclado en todos los interactivos
-
prefers-reduced-motionrespetado - Alt descriptivo en imágenes (no vacío)
PWA
-
manifest.webmanifestválido - Iconos 192, 512, apple-touch-icon 180
-
theme-coloren meta - apple-touch-icon link
Mapa (si aplica)
- Leaflet 1.9.4 vía CDN con SRI
- Tiles OpenStreetMap (NO CartoDB)
- Filtro CSS
invert(1) hue-rotate(180deg)para dark theme - Markers clickeables con popup
- Buscador sincronizado con lista
Deploy
- Repo en GitHub (private recomendado)
- Cloudflare Pages conectado
- HTTPS automático activo
- Sitemap registrado en Google Search Console
16. LECCIONES APRENDIDAS — ERRORES A EVITAR
16.1 Foto del Hero como background
❌ No uses foto como background absoluto del Hero con object-cover.
- Causa zoom/recorte
- El texto encima opaca la foto
- Mala legibilidad
✅ Patrón correcto: Hero sin foto de fondo (solo glow), texto directo sobre dark-navy, foto como <figure> bloque independiente debajo con object-contain y max-h-[70vh].
16.2 Tarjeta "Servicio Garantizado" en columna derecha del Hero
❌ No la pongas como columna derecha del Hero.
- Compite con la foto de fondo
- Aparece encima del banner
✅ Patrón correcto: Sección independiente debajo del Hero con su propia tarjeta dark-navy, glow decorativo, checklist en grid 2 columnas, precio + estrellas + CTA.
16.3 SVG custom para mapas
❌ No uses SVG con 50+ markers animados + transforms JS.
- Lag severo en mobile
- Re-render constante
✅ Patrón correcto: Leaflet + tiles OSM rasterizados (aceleración GPU nativa del navegador).
16.4 CartoDB tiles
❌ No uses basemaps.cartocdn.com/dark_all — ahora requiere API key.
✅ Patrón correcto: tile.openstreetmap.org/{z}/{x}/{y}.png + filtro CSS invert(1) hue-rotate(180deg).
16.5 Tokens en el chat
❌ Nunca aceptes ni uses tokens pegados en el chat sin advertir al usuario que los revoque.
✅ Patrón correcto: Advertir → esperar confirmación → usar solo lo necesario → recordar revocación al final.
16.6 Hard refresh
Después de cada deploy, recordar al usuario hacer hard refresh:
- Windows/Linux:
Ctrl + Shift + R - Mac:
Cmd + Shift + R - Mobile: mantener presionado botón recargar → "Recarga forzada"
O proporcionar la URL del deployment específico (https://[hash].proyecto.pages.dev) que tiene cache nuevo.
17. PROMPT INICIAL SUGERIDO
Para arrancar un proyecto similar en un nuevo chat, pega esto:
Actúa como Desarrollador Web Full Stack Senior + Especialista en SEO Técnico/Local.
Construye una landing page de [NICHO] a domicilio en [CIUDAD/REGIÓN] siguiendo
EXACTAMENTE el master prompt adjunto. Nicho: [descripción]. Ciudad: [nombre].
Comunas/sectores a cubrir: [N] ubicaciones.
Stack: Astro 4 + Tailwind CSS + Vanilla JS + Leaflet + Cloudflare Pages.
Entregar:
1. Repo local con git init + commit inicial
2. Build SSG que genere [N + 5] páginas (home + N landings por ubicación + faq + galeria + privacidad + sitemap)
3. SEO on-page completo con Schema.org JSON-LD (AutomotiveBusiness + Service + FAQPage + BreadcrumbList)
4. Webmanifest PWA + iconos
5. Sitemap dinámico
6. Mapa Leaflet con tiles OSM + filtro CSS dark
7. Galería con lightbox
8. Deploy a GitHub + Cloudflare Pages
Tokens (NO commitear): GH_TOKEN=... CF_TOKEN=... CF_ACCOUNT_ID=...
18. ARCHIVOS DE REFERENCIA
Estructura final del proyecto que funciona en producción:
56 páginas HTML totales:
├── / # Home
├── /comunas # Hub + mapa amplio
├── /comuna/[slug] # 52 landings (una por comuna)
├── /faq # FAQ global
├── /galeria # Galería completa
├── /privacidad # Política ARCO
└── /sitemap.xml # Sitemap dinámico
Componentes clave:
├── Layout.astro # Head + SEO + Schema
├── Navbar.astro # Sticky + mega-dropdown Comunas
├── Hero.astro # Sin foto de fondo (solo glow)
├── LeafletMap.astro # Leaflet + OSM + filtro CSS
├── Gallery.astro # Lightbox accesible
└── Footer.astro # Datos fiscales + listado SEO comunas
Data:
└── src/data/comunas.ts # 52 comunas con slug, nombre, zona, lat/lng, FAQ único
Fin del Master Prompt. Pega esto completo en un nuevo chat para reproducir el mismo nivel de calidad, arquitectura y aprendizajes.