feat(404): preparar infraestructura para imagen IA del robot, SVG fallback funcional
- src/pages/404.astro refactorizado: usa <picture> con AVIF/WebP/PNG + onerror que activa SVG inline fallback - public/images/404/ creado con README.md explicando el workflow de optimizacion - El SVG procedural del robot (con mate, vapor, ojos medio cerrados, mejillas coral) queda como fallback visible mientras se espera la imagen IA - Cuando Mauri suba el robot_404.png (o avif/webp), basta con copiar a public/images/404/ y rebuild Pendiente: que Mauri suba el archivo robot_404.png a public/images/404/ (o confirme la ruta donde lo dejó)
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
# 404 Robot Image Assets
|
||||
|
||||
Cuando se suba la imagen final del robot (PNG/WebP/AVIF), debe ir en esta carpeta:
|
||||
|
||||
```
|
||||
public/images/404/
|
||||
├── robot-mate.png (fallback, mínimo 480x480)
|
||||
├── robot-mate.webp (preferido moderno, <50KB)
|
||||
└── robot-mate.avif (óptimo, <30KB)
|
||||
```
|
||||
|
||||
## Cómo se usa
|
||||
|
||||
El `src/pages/404.astro` usa `<picture>` con esta estructura:
|
||||
|
||||
```html
|
||||
<picture>
|
||||
<source type="image/avif" srcset="/images/404/robot-mate.avif" />
|
||||
<source type="image/webp" srcset="/images/404/robot-mate.webp" />
|
||||
<img src="/images/404/robot-mate.png" alt="..." onerror="fallback" />
|
||||
</picture>
|
||||
```
|
||||
|
||||
Si **ninguna** de las versiones existe, el `onerror` muestra el SVG inline de respaldo (mismo robot dibujado en SVG).
|
||||
|
||||
## Generar las versiones optimizadas
|
||||
|
||||
Una vez que se tenga la imagen original (PNG o JPG) en `public/images/404/robot-mate-original.png`:
|
||||
|
||||
```bash
|
||||
cd public/images/404
|
||||
|
||||
# WebP
|
||||
convert robot-mate-original.png -quality 82 -resize 600x600 robot-mate.webp
|
||||
|
||||
# AVIF
|
||||
avifenc --min 25 --max 35 --speed 6 -o robot-mate.avif robot-mate-original.png
|
||||
|
||||
# PNG fallback
|
||||
convert robot-mate-original.png -quality 90 -resize 480x480 robot-mate.png
|
||||
```
|
||||
|
||||
## Reemplazo
|
||||
|
||||
1. Mauri guarda la imagen IA final (la del robot vago con mate) en `public/images/404/`
|
||||
2. Correr el script de arriba para generar AVIF/WebP/PNG
|
||||
3. Rebuild + deploy
|
||||
4. El sitio muestra la imagen IA automáticamente; si no carga, fallback SVG
|
||||
+119
-104
@@ -11,124 +11,140 @@ import BaseLayout from '@/layouts/BaseLayout.astro';
|
||||
<div class="relative max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 w-full">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-12 items-center">
|
||||
|
||||
<!-- Robot SVG -->
|
||||
<div class="order-2 lg:order-1" aria-hidden="true">
|
||||
<svg viewBox="0 0 480 480" xmlns="http://www.w3.org/2000/svg" class="w-full max-w-md mx-auto">
|
||||
<defs>
|
||||
<linearGradient id="bg-grad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#FAF6EE" stop-opacity="0"/>
|
||||
<stop offset="100%" stop-color="#EE7623" stop-opacity="0.08"/>
|
||||
</linearGradient>
|
||||
<filter id="soft-shadow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feGaussianBlur in="SourceAlpha" stdDeviation="8"/>
|
||||
<feOffset dx="0" dy="4" result="offsetblur"/>
|
||||
<feComponentTransfer><feFuncA type="linear" slope="0.15"/></feComponentTransfer>
|
||||
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
<picture>
|
||||
<source type="image/avif" srcset="/images/404/robot-mate.avif" />
|
||||
<source type="image/webp" srcset="/images/404/robot-mate.webp" />
|
||||
<img
|
||||
src="/images/404/robot-mate.png"
|
||||
alt="Robot tomando mate con cara de vago"
|
||||
width="480"
|
||||
height="480"
|
||||
class="w-full max-w-md mx-auto h-auto"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
onerror="this.style.display='none'; document.getElementById('robot-fallback').style.display='block';"
|
||||
/>
|
||||
</picture>
|
||||
|
||||
<circle cx="240" cy="240" r="220" fill="url(#bg-grad)"/>
|
||||
<div id="robot-fallback" style="display:none;" aria-hidden="true">
|
||||
<svg viewBox="0 0 480 480" xmlns="http://www.w3.org/2000/svg" class="w-full max-w-md mx-auto">
|
||||
<defs>
|
||||
<linearGradient id="bg-grad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#FAF6EE" stop-opacity="0"/>
|
||||
<stop offset="100%" stop-color="#EE7623" stop-opacity="0.08"/>
|
||||
</linearGradient>
|
||||
<filter id="soft-shadow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feGaussianBlur in="SourceAlpha" stdDeviation="8"/>
|
||||
<feOffset dx="0" dy="4" result="offsetblur"/>
|
||||
<feComponentTransfer><feFuncA type="linear" slope="0.15"/></feComponentTransfer>
|
||||
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<g opacity="0.35">
|
||||
<rect x="60" y="80" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="68" y="80" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="76" y="80" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="404" y="80" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="412" y="80" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="68" y="88" width="8" height="8" fill="#FFCBA1" rx="1"/>
|
||||
<rect x="412" y="88" width="8" height="8" fill="#FFCBA1" rx="1"/>
|
||||
<rect x="60" y="380" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="68" y="380" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="404" y="380" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="412" y="380" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="68" y="388" width="8" height="8" fill="#FFCBA1" rx="1"/>
|
||||
<rect x="412" y="388" width="8" height="8" fill="#FFCBA1" rx="1"/>
|
||||
</g>
|
||||
<circle cx="240" cy="240" r="220" fill="url(#bg-grad)"/>
|
||||
|
||||
<ellipse cx="240" cy="420" rx="100" ry="10" fill="#EE7623" opacity="0.12"/>
|
||||
<g opacity="0.35">
|
||||
<rect x="60" y="80" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="68" y="80" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="76" y="80" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="404" y="80" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="412" y="80" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="68" y="88" width="8" height="8" fill="#FFCBA1" rx="1"/>
|
||||
<rect x="412" y="88" width="8" height="8" fill="#FFCBA1" rx="1"/>
|
||||
<rect x="60" y="380" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="68" y="380" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="404" y="380" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="412" y="380" width="8" height="8" fill="#FA9F5C" rx="1"/>
|
||||
<rect x="68" y="388" width="8" height="8" fill="#FFCBA1" rx="1"/>
|
||||
<rect x="412" y="388" width="8" height="8" fill="#FFCBA1" rx="1"/>
|
||||
</g>
|
||||
|
||||
<g filter="url(#soft-shadow)">
|
||||
<rect x="160" y="240" width="160" height="140" rx="20" fill="#E8E2D5" stroke="#EE7623" stroke-width="3"/>
|
||||
<circle cx="200" cy="280" r="6" fill="#EE7623">
|
||||
<animate attributeName="opacity" values="1;0.3;1" dur="1.8s" repeatCount="indefinite"/>
|
||||
<ellipse cx="240" cy="420" rx="100" ry="10" fill="#EE7623" opacity="0.12"/>
|
||||
|
||||
<g filter="url(#soft-shadow)">
|
||||
<rect x="160" y="240" width="160" height="140" rx="20" fill="#E8E2D5" stroke="#EE7623" stroke-width="3"/>
|
||||
<circle cx="200" cy="280" r="6" fill="#EE7623">
|
||||
<animate attributeName="opacity" values="1;0.3;1" dur="1.8s" repeatCount="indefinite"/>
|
||||
</circle>
|
||||
<circle cx="200" cy="280" r="6" fill="#EE7623" opacity="0.3"/>
|
||||
<rect x="220" y="276" width="80" height="8" rx="2" fill="#1A1612" opacity="0.15"/>
|
||||
<rect x="220" y="290" width="60" height="6" rx="2" fill="#1A1612" opacity="0.1"/>
|
||||
<circle cx="280" cy="340" r="14" fill="#FAF6EE" stroke="#EE7623" stroke-width="2"/>
|
||||
<circle cx="280" cy="340" r="6" fill="#EE7623"/>
|
||||
</g>
|
||||
|
||||
<g filter="url(#soft-shadow)">
|
||||
<rect x="170" y="100" width="140" height="140" rx="24" fill="#F5EFE3" stroke="#EE7623" stroke-width="3"/>
|
||||
</g>
|
||||
|
||||
<line x1="240" y1="100" x2="240" y2="68" stroke="#EE7623" stroke-width="4" stroke-linecap="round"/>
|
||||
<circle cx="240" cy="60" r="8" fill="#EE7623">
|
||||
<animate attributeName="r" values="6;9;6" dur="2s" repeatCount="indefinite"/>
|
||||
</circle>
|
||||
<circle cx="200" cy="280" r="6" fill="#EE7623" opacity="0.3"/>
|
||||
<rect x="220" y="276" width="80" height="8" rx="2" fill="#1A1612" opacity="0.15"/>
|
||||
<rect x="220" y="290" width="60" height="6" rx="2" fill="#1A1612" opacity="0.1"/>
|
||||
<circle cx="280" cy="340" r="14" fill="#FAF6EE" stroke="#EE7623" stroke-width="2"/>
|
||||
<circle cx="280" cy="340" r="6" fill="#EE7623"/>
|
||||
</g>
|
||||
|
||||
<g filter="url(#soft-shadow)">
|
||||
<rect x="170" y="100" width="140" height="140" rx="24" fill="#F5EFE3" stroke="#EE7623" stroke-width="3"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M 200 165 Q 210 172 220 165" stroke="#1A1612" stroke-width="4" fill="none" stroke-linecap="round"/>
|
||||
<line x1="195" y1="158" x2="225" y2="155" stroke="#1A1612" stroke-width="2" stroke-linecap="round" opacity="0.5"/>
|
||||
<path d="M 195 158 Q 210 168 225 158" stroke="#1A1612" stroke-width="3" fill="none" stroke-linecap="round"/>
|
||||
|
||||
<line x1="240" y1="100" x2="240" y2="68" stroke="#EE7623" stroke-width="4" stroke-linecap="round"/>
|
||||
<circle cx="240" cy="60" r="8" fill="#EE7623">
|
||||
<animate attributeName="r" values="6;9;6" dur="2s" repeatCount="indefinite"/>
|
||||
</circle>
|
||||
<ellipse cx="260" cy="167" rx="10" ry="12" fill="#FAF6EE" stroke="#1A1612" stroke-width="2"/>
|
||||
<circle cx="263" cy="170" r="5" fill="#1A1612"/>
|
||||
<circle cx="264" cy="167" r="2" fill="#FAF6EE"/>
|
||||
</g>
|
||||
|
||||
<g>
|
||||
<path d="M 200 165 Q 210 172 220 165" stroke="#1A1612" stroke-width="4" fill="none" stroke-linecap="round"/>
|
||||
<line x1="195" y1="158" x2="225" y2="155" stroke="#1A1612" stroke-width="2" stroke-linecap="round" opacity="0.5"/>
|
||||
<path d="M 195 158 Q 210 168 225 158" stroke="#1A1612" stroke-width="3" fill="none" stroke-linecap="round"/>
|
||||
<ellipse cx="190" cy="195" rx="8" ry="4" fill="#FA9F5C" opacity="0.6"/>
|
||||
<ellipse cx="290" cy="195" rx="8" ry="4" fill="#FA9F5C" opacity="0.6"/>
|
||||
|
||||
<ellipse cx="260" cy="167" rx="10" ry="12" fill="#FAF6EE" stroke="#1A1612" stroke-width="2"/>
|
||||
<circle cx="263" cy="170" r="5" fill="#1A1612"/>
|
||||
<circle cx="264" cy="167" r="2" fill="#FAF6EE"/>
|
||||
</g>
|
||||
<ellipse cx="240" cy="210" rx="14" ry="10" fill="#1A1612"/>
|
||||
<ellipse cx="240" cy="212" rx="10" ry="6" fill="#FAF6EE"/>
|
||||
<line x1="240" y1="205" x2="240" y2="218" stroke="#1A1612" stroke-width="1.5" opacity="0.3"/>
|
||||
|
||||
<ellipse cx="190" cy="195" rx="8" ry="4" fill="#FA9F5C" opacity="0.6"/>
|
||||
<ellipse cx="290" cy="195" rx="8" ry="4" fill="#FA9F5C" opacity="0.6"/>
|
||||
<g filter="url(#soft-shadow)">
|
||||
<rect x="120" y="180" width="24" height="80" rx="12" fill="#F5EFE3" stroke="#EE7623" stroke-width="3" transform="rotate(-25 132 220)"/>
|
||||
<circle cx="110" cy="170" r="18" fill="#F5EFE3" stroke="#EE7623" stroke-width="3"/>
|
||||
<line x1="92" y1="160" x2="86" y2="152" stroke="#EE7623" stroke-width="3" stroke-linecap="round"/>
|
||||
<line x1="98" y1="155" x2="94" y2="145" stroke="#EE7623" stroke-width="3" stroke-linecap="round"/>
|
||||
<line x1="106" y1="153" x2="104" y2="142" stroke="#EE7623" stroke-width="3" stroke-linecap="round"/>
|
||||
<line x1="114" y1="156" x2="115" y2="146" stroke="#EE7623" stroke-width="3" stroke-linecap="round"/>
|
||||
<line x1="120" y1="162" x2="124" y2="155" stroke="#EE7623" stroke-width="3" stroke-linecap="round"/>
|
||||
</g>
|
||||
|
||||
<ellipse cx="240" cy="210" rx="14" ry="10" fill="#1A1612"/>
|
||||
<ellipse cx="240" cy="212" rx="10" ry="6" fill="#FAF6EE"/>
|
||||
<line x1="240" y1="205" x2="240" y2="218" stroke="#1A1612" stroke-width="1.5" opacity="0.3"/>
|
||||
<g filter="url(#soft-shadow)">
|
||||
<rect x="336" y="220" width="24" height="80" rx="12" fill="#F5EFE3" stroke="#EE7623" stroke-width="3" transform="rotate(30 348 260)"/>
|
||||
<circle cx="358" cy="290" r="16" fill="#F5EFE3" stroke="#EE7623" stroke-width="3"/>
|
||||
</g>
|
||||
|
||||
<g filter="url(#soft-shadow)">
|
||||
<rect x="120" y="180" width="24" height="80" rx="12" fill="#F5EFE3" stroke="#EE7623" stroke-width="3" transform="rotate(-25 132 220)"/>
|
||||
<circle cx="110" cy="170" r="18" fill="#F5EFE3" stroke="#EE7623" stroke-width="3"/>
|
||||
<line x1="92" y1="160" x2="86" y2="152" stroke="#EE7623" stroke-width="3" stroke-linecap="round"/>
|
||||
<line x1="98" y1="155" x2="94" y2="145" stroke="#EE7623" stroke-width="3" stroke-linecap="round"/>
|
||||
<line x1="106" y1="153" x2="104" y2="142" stroke="#EE7623" stroke-width="3" stroke-linecap="round"/>
|
||||
<line x1="114" y1="156" x2="115" y2="146" stroke="#EE7623" stroke-width="3" stroke-linecap="round"/>
|
||||
<line x1="120" y1="162" x2="124" y2="155" stroke="#EE7623" stroke-width="3" stroke-linecap="round"/>
|
||||
</g>
|
||||
<g transform="translate(330 280)">
|
||||
<ellipse cx="22" cy="28" rx="24" ry="20" fill="#1A1612"/>
|
||||
<ellipse cx="14" cy="22" rx="6" ry="4" fill="#FAF6EE" opacity="0.2"/>
|
||||
<ellipse cx="22" cy="14" rx="20" ry="5" fill="#EE7623"/>
|
||||
<ellipse cx="22" cy="13" rx="18" ry="3" fill="#FFCBA1"/>
|
||||
<rect x="35" y="6" width="8" height="14" rx="2" fill="#8A8580"/>
|
||||
<rect x="36" y="2" width="6" height="6" rx="1" fill="#C8C2B8"/>
|
||||
<ellipse cx="22" cy="11" rx="14" ry="2" fill="#2E7D5B" opacity="0.8"/>
|
||||
</g>
|
||||
|
||||
<g filter="url(#soft-shadow)">
|
||||
<rect x="336" y="220" width="24" height="80" rx="12" fill="#F5EFE3" stroke="#EE7623" stroke-width="3" transform="rotate(30 348 260)"/>
|
||||
<circle cx="358" cy="290" r="16" fill="#F5EFE3" stroke="#EE7623" stroke-width="3"/>
|
||||
</g>
|
||||
<g opacity="0.4">
|
||||
<path d="M 380 270 Q 384 262 380 254" stroke="#8A8580" stroke-width="2" fill="none" stroke-linecap="round">
|
||||
<animate attributeName="opacity" values="0;0.6;0" dur="2.5s" repeatCount="indefinite"/>
|
||||
</path>
|
||||
<path d="M 392 270 Q 396 262 392 254" stroke="#8A8580" stroke-width="2" fill="none" stroke-linecap="round">
|
||||
<animate attributeName="opacity" values="0;0.6;0" dur="2.5s" begin="0.5s" repeatCount="indefinite"/>
|
||||
</path>
|
||||
<path d="M 386 274 Q 390 266 386 258" stroke="#8A8580" stroke-width="2" fill="none" stroke-linecap="round">
|
||||
<animate attributeName="opacity" values="0;0.6;0" dur="2.5s" begin="1s" repeatCount="indefinite"/>
|
||||
</path>
|
||||
</g>
|
||||
|
||||
<g transform="translate(330 280)">
|
||||
<ellipse cx="22" cy="28" rx="24" ry="20" fill="#1A1612"/>
|
||||
<ellipse cx="14" cy="22" rx="6" ry="4" fill="#FAF6EE" opacity="0.2"/>
|
||||
<ellipse cx="22" cy="14" rx="20" ry="5" fill="#EE7623"/>
|
||||
<ellipse cx="22" cy="13" rx="18" ry="3" fill="#FFCBA1"/>
|
||||
<rect x="35" y="6" width="8" height="14" rx="2" fill="#8A8580"/>
|
||||
<rect x="36" y="2" width="6" height="6" rx="1" fill="#C8C2B8"/>
|
||||
<ellipse cx="22" cy="11" rx="14" ry="2" fill="#2E7D5B" opacity="0.8"/>
|
||||
</g>
|
||||
|
||||
<g opacity="0.4">
|
||||
<path d="M 380 270 Q 384 262 380 254" stroke="#8A8580" stroke-width="2" fill="none" stroke-linecap="round">
|
||||
<animate attributeName="opacity" values="0;0.6;0" dur="2.5s" repeatCount="indefinite"/>
|
||||
</path>
|
||||
<path d="M 392 270 Q 396 262 392 254" stroke="#8A8580" stroke-width="2" fill="none" stroke-linecap="round">
|
||||
<animate attributeName="opacity" values="0;0.6;0" dur="2.5s" begin="0.5s" repeatCount="indefinite"/>
|
||||
</path>
|
||||
<path d="M 386 274 Q 390 266 386 258" stroke="#8A8580" stroke-width="2" fill="none" stroke-linecap="round">
|
||||
<animate attributeName="opacity" values="0;0.6;0" dur="2.5s" begin="1s" repeatCount="indefinite"/>
|
||||
</path>
|
||||
</g>
|
||||
|
||||
<g filter="url(#soft-shadow)">
|
||||
<rect x="195" y="380" width="30" height="50" rx="10" fill="#F5EFE3" stroke="#EE7623" stroke-width="3"/>
|
||||
<rect x="255" y="380" width="30" height="50" rx="10" fill="#F5EFE3" stroke="#EE7623" stroke-width="3"/>
|
||||
<ellipse cx="210" cy="432" rx="22" ry="8" fill="#EE7623"/>
|
||||
<ellipse cx="270" cy="432" rx="22" ry="8" fill="#EE7623"/>
|
||||
</g>
|
||||
</svg>
|
||||
<g filter="url(#soft-shadow)">
|
||||
<rect x="195" y="380" width="30" height="50" rx="10" fill="#F5EFE3" stroke="#EE7623" stroke-width="3"/>
|
||||
<rect x="255" y="380" width="30" height="50" rx="10" fill="#F5EFE3" stroke="#EE7623" stroke-width="3"/>
|
||||
<ellipse cx="210" cy="432" rx="22" ry="8" fill="#EE7623"/>
|
||||
<ellipse cx="270" cy="432" rx="22" ry="8" fill="#EE7623"/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="order-1 lg:order-2 text-center lg:text-left">
|
||||
@@ -158,7 +174,6 @@ import BaseLayout from '@/layouts/BaseLayout.astro';
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Server-side include (SSI) — cPanel pone el HTML y Apache lo procesa -->
|
||||
<!--#if expr="$REMOTE_ADDR" -->
|
||||
<div class="mt-10 pt-6 border-t" style="border-color: var(--hds-line);">
|
||||
<p class="text-xs font-semibold tracking-[0.2em] uppercase mb-3" style="color: var(--color-hds-naranja);">
|
||||
|
||||
Reference in New Issue
Block a user