Completa antes de enviar
[nombre del servidor][nombre del estudio][a qué se dedica, para quién][ciudad, barrio][3 servicios][correo][teléfono][número de WhatsApp][dirección][dominio][[NAV]
En mi servidor de hosting de Opus Growth [nombre del servidor], crea un sitio de portfolio estático y rápido para [nombre del estudio] que se sienta como los sitios de agencia interactivos hechos en Webflow, pero sin usar Webflow. Estudio: [a qué se dedica, para quién], ciudad y barrio: [ciudad, barrio]. Servicios: [3 servicios]. Proyectos: [para cada uno: nombre, tipo de trabajo, año, una frase sobre el problema, otra sobre la solución, enlace de la imagen]. Contacto: [correo], [teléfono], [número de WhatsApp], [dirección]. Dominio: [dominio].
Páginas: inicio (hero, índice de trabajos seleccionados, qué hacemos, proceso, preguntas frecuentes, llamada a la acción final), trabajos (/isler/: galería más problema, trabajo realizado y nota de entrega de cada proyecto), estudio (/hakkimizda/), contacto (/iletisim/, sin formulario; correo, WhatsApp con mensaje prellenado y teléfono), privacidad (/gizlilik/) y 404.html. Sin datos aprobados por el cliente, no escribas porcentajes ni cifras de crecimiento para los resultados de los proyectos; describe el resultado con palabras.
Estilo: moderno brutalista. Esquinas rectas, líneas de cuadrícula visibles de 1 px, una grotesca display en mayúsculas y en negrita (por ejemplo Clash Grotesk) y una tipografía de texto sobria (por ejemplo Supreme), un único acento fluorescente usado solo como fondo con texto negro encima. Los estados hover cambian color y fondo; el anillo de foco es grueso y visible sobre cualquier fondo.
Reglas de interacción (la sensación de Webflow IX2, sin librería):
1. NO cargues GSAP ni Lenis. Escribe las interacciones en un único archivo JS puro y pequeño (IntersectionObserver y requestAnimationFrame) y cárgalo con defer solo en las páginas de inicio y trabajos. Ningún script en las demás páginas.
2. Elemento distintivo, el índice "Trabajos seleccionados": cada fila es un enlace real al proyecto y lleva la ruta de la imagen de vista previa en un atributo data-img. Por defecto (sin JS o en un dispositivo táctil) cada fila muestra una imagen pequeña en el flujo. Solo en dispositivos que cumplan `(hover: hover) and (pointer: fine)` y que no pidan movimiento reducido, el JS añade una clase cursor-fx a `<html>`, oculta las imágenes en línea y muestra una única caja de vista previa que sigue al puntero. Mueve la caja con variables CSS y transform: translate3d en lugar de left y top, y detén el bucle de requestAnimationFrame cuando el puntero esté quieto. Con el foco del teclado, la misma vista previa se abre fija junto a la fila y se cierra cuando el foco sale.
3. Añade el anillo de cursor personalizado solo bajo la misma condición; nunca ocultes el cursor nativo, marca el anillo con aria-hidden y haz que crezca sobre los enlaces.
4. Transiciones de sección: los títulos de sección se abren de izquierda a derecha con clip-path al hacer scroll. El JS aplica el estado inicial oculto solo a los títulos que están por debajo de la pantalla cuando se abre la página; el contenido de la primera pantalla nunca se oculta. Llama al atributo data-reveal; design-check reconoce el movimiento por ese nombre y, si no, avisa "sin movimiento".
5. Galería Swiper solo en la página de trabajos. Sin JS, el HTML de la galería es una tira horizontal CSS con scroll-snap, y los botones anterior y siguiente permanecen ocultos hasta que Swiper arranca. Descarga el bundle js y css de Swiper 14 en `assets/vendor/` con site_fetch. Cárgalo cuando el puntero entre en la galería, al tocar, al recibir foco o en el primer scroll de la página. En la demo, cargarlo cuando la galería se acercaba al viewport empujó el LCP móvil a 3 s por el bundle de 150 KB (Performance 94); cargarlo en la primera interacción dio 99. Activa los módulos Navigation, Keyboard y A11y con mensajes en turco, y pon la velocidad de transición en 0 con movimiento reducido.
6. Construye las diapositivas con div en lugar de ul y li. Swiper asigna role="group" a las diapositivas; sobre li ese rol provocó errores de aria-allowed-role y de lista, y Accessibility bajó a 96.
Configuración y trampas conocidas (cada una bajó una puntuación en las mediciones de la demo, no te las saltes):
1. Si ya hay un sitio en vivo en el servidor, avísame primero, porque la configuración inicial sobrescribe index.html y la carpeta assets. Haz una vista previa de scaffold_site con confirm=false y llámalo con confirm=true tras mi aprobación. Después lee site_design_guide y site_seo_guide. Antes de escribir código, pon la dirección de diseño (tipografía, color, cuadrícula, elemento distintivo, lenguaje de movimiento y las librerías que NO se cargarán) en un ART.md breve fuera de assets y muéstramelo.
2. Compila Tailwind en lugar de cargarlo desde el CDN. Instálalo con site_run_command y background=true: `npm i -D tailwindcss@3`, y a continuación sigue con site_command_status. Las rutas content de `tailwind.config.js` deben cubrir todos los archivos HTML, las plantillas y cualquier archivo JS que escriba nombres de clase. `_src/tw.css` contiene la línea `@import "../assets/app.css";` y las tres líneas `@tailwind`; compílalo en un único archivo con `npx tailwindcss -c tailwind.config.js -i _src/tw.css -o assets/site.css --minify`. Elimina el script cdn.tailwindcss.com y el tailwind.config en línea de todas las páginas y enlaza solo `/assets/site.css`. Recompila después de cada cambio de HTML.
3. Aloja las fuentes tú mismo. Lee el CSS de las familias de Fontshare que elijas, descarga el archivo woff2 de cada peso en `assets/fonts/` con site_fetch y escribe las reglas @font-face con `font-display: swap` en `assets/app.css`; design-check busca ahí una fuente personalizada. Comprueba el nombre de font-family en el CSS descargado, porque Fontshare puede devolver otra familia cuando un peso no existe. Haz preload de la fuente del título de la primera pantalla y de la fuente del texto en cada página con `<link rel="preload" as="font" type="font/woff2" crossorigin>`; en la demo esto eliminó el desplazamiento de diseño causado por el cambio de fuente (CLS de 0,024 a 0). La mayoría de las fuentes de Fontshare no tienen el glifo ₺, así que escribe "TL" en los precios.
4. Haz el menú y el pie de página en HTML estático. No cargues chrome.js ni site.config.js en las páginas. Escribe un pequeño `chrome-stamp.mjs` que lea la lista de navegación de site.config.js y estampe `_src/header.tpl` y `_src/footer.tpl` entre los marcadores `<!-- nav:start --><!-- nav:end -->` y `<!-- footer:start --><!-- footer:end -->` de cada página, añadiendo aria-current="page" al enlace actual. No des a las plantillas extensión .html y usa marcadores como `[[NAV]]` en lugar de `{{...}}`, de lo contrario design-check y seo-check las leen como páginas sin terminar. Construye el menú móvil sin JS con `<details>`. Mantén el nombre del negocio, la dirección y el teléfono en el pie como texto plano.
5. Convierte las imágenes al descargarlas con site_fetch: escribe la misma foto en archivos separados con resize="480x", "800x" y "1200x", image_format="webp", quality=65. Da a cada `<img>` srcset, sizes, width y height. La imagen principal de la primera pantalla recibe fetchpriority="high" y nunca es lazy; las demás reciben loading="lazy" decoding="async". Si la imagen principal llena la pantalla del móvil, sirve en móvil un recorte más ancho y pequeño con `<picture>` (en la demo el hero móvil pasó de 89 KB a 43 KB).
6. Crea un favicon PNG de 48 px a partir del logo con site_fetch y añade `<link rel="icon">` a cada página. Sin él, el navegador registra un 404 y Best Practices baja a 96.
7. Reglas del validador HTML: empieza cada documento con un `<!DOCTYPE html>` en mayúsculas (los archivos iniciales del kit lo traen en minúsculas), usa ` ` para los espacios en el texto visible de los enlaces tel:, no uses nunca un atributo style="" y da a cada botón type="button".
SEO, AEO y GEO:
1. Usa URLs de directorio con barra final (/isler/, /hakkimizda/, /iletisim/, /gizlilik/). Rellena el bloque seo de site.config.js y ejecuta `node seo-stamp.mjs`. Escribe el schema específico de cada página (inicio WebPage y FAQPage; trabajos CollectionPage con un CreativeWork por proyecto dentro de hasPart; estudio AboutPage; contacto ContactPage; BreadcrumbList en las páginas internas. Para un estudio con oficina física usa businessType ProfessionalService) en bloques `<script type="application/ld+json">` separados y enlázalo con el grafo base mediante @id. No entierres BreadcrumbList dentro de un @graph; dale su propio bloque, porque es la única forma en que seo-check lo detecta.
2. Títulos de 48 a 60 caracteres (seo-check marca como error todo lo que pase de 65), descripciones de 145 a 158 caracteres, un solo h1 por página. Cada página necesita al menos 150 palabras de contenido principal; las páginas de contacto y privacidad suelen quedarse cortas.
3. El primer párrafo de cada página responde directamente a la pregunta de la página. Escribe unas preguntas frecuentes propias de la página con `<details>` y márcalas como FAQPage. Muestra la organización que publica y una fecha de "Última actualización" con `<time>`.
4. En robots.txt, escribe tu decisión con su motivo para GPTBot, OAI-SearchBot, ChatGPT-User, ClaudeBot, Claude-User, Claude-SearchBot, PerplexityBot, Perplexity-User, Google-Extended, Applebot-Extended, Bingbot y CCBot, y apunta al sitemap. sitemap.xml lleva fechas lastmod reales. llms.txt contiene un resumen exacto del sitio en dos frases y la lista de páginas clave.
5. No inventes nada: ni reseñas, ni valoraciones, ni premios, ni cifras de clientes, ni certificados, ni horarios, ni coordenadas, ni precios, salvo que yo te los dé. Deja fuera del schema los campos desconocidos.
Controles (en orden; no lo des por terminado hasta que todos pasen):
1. Con site_run_command ejecuta `node chrome-stamp.mjs`, la compilación de Tailwind, `node seo-stamp.mjs`, `node seo-check.mjs` (0 errores, 0 avisos), `node design-check.mjs` (0 errores; justifica cualquier aviso restante) y `npx html-validate "**/*.html"` (0 errores).
2. Revisa cada página con site_preview, view="mobile" y view="desktop". site_preview captura la página con el movimiento desactivado (reduced-motion), así que si en esa imagen falta contenido, el estado sin movimiento está roto. En las capturas de página completa, las imágenes lazy más abajo pueden aparecer vacías; eso no es un error, pero comprueba sus rutas.
3. Ejecuta core_web_vitals para cada página con strategy="mobile" y strategy="desktop". Para aprobar: en móvil, Performance de al menos 95 y Accessibility, Best Practices y SEO en 100; en escritorio, las cuatro de al menos 95. En una página que no pase, usa resources=true para encontrar el archivo que la frena, corrígelo y vuelve a medir. Después ejecuta seo_audit en la página de inicio con strategy="mobile" y runs=2. La lista de peticiones de red no debe contener ningún host que no sea tu propio dominio.
4. Sin scroll horizontal a 360, 390, 768 y 1440 px de ancho, áreas táctiles de al menos 44 px, sin errores en la consola.
Comprobación de la interacción: site_preview no puede mostrar efectos de hover ni de cursor. Dime cómo comprobar en un navegador de escritorio que la vista previa sigue al puntero sobre las filas del índice, que se abre junto a la fila al navegar con Tab, que un teléfono muestra las imágenes en línea y que la galería se desliza con el dedo.
Tras publicar: haz una vista previa de la regla `/assets/* Cache-Control: public, max-age=31536000, immutable` con site_headers y aplícala tras mi aprobación; a partir de entonces, cambia el nombre de los archivos CSS o JS cuando cambien (site-v2.css, etc.). Envía sitemap.xml con gsc_submit_sitemap y revisa la página de inicio con gsc_url_inspect. Termina con una tabla de puntuaciones por página (página, cuatro puntuaciones móviles, cuatro de escritorio, LCP, CLS), los resultados de los controles y la lista de correcciones que aplicaste.