bmad-plus 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/oveanet-pack/animated-website/DEPLOYMENT.md +104 -0
- package/oveanet-pack/animated-website/README.md +63 -0
- package/oveanet-pack/animated-website/agent/animated-website-agent.md +325 -0
- package/oveanet-pack/animated-website/agent.yaml +63 -0
- package/oveanet-pack/animated-website/templates/animated-website-workflow.md +55 -0
- package/oveanet-pack/seo-audit-360/DEPLOYMENT.md +115 -0
- package/oveanet-pack/seo-audit-360/README.md +60 -0
- package/oveanet-pack/seo-audit-360/agent/seo-geo-360-auditor.md +441 -0
- package/oveanet-pack/seo-audit-360/agent.yaml +71 -0
- package/oveanet-pack/seo-audit-360/checklist.md +140 -0
- package/oveanet-pack/seo-audit-360/pagespeed-playbook.md +320 -0
- package/oveanet-pack/seo-audit-360/templates/llms.txt +73 -0
- package/oveanet-pack/seo-audit-360/templates/robots.txt +38 -0
- package/oveanet-pack/seo-audit-360/templates/schema-templates.json +116 -0
- package/oveanet-pack/universal-backup/DEPLOYMENT.md +80 -0
- package/oveanet-pack/universal-backup/README.md +58 -0
- package/oveanet-pack/universal-backup/agent/backup-agent.md +71 -0
- package/oveanet-pack/universal-backup/agent.yaml +45 -0
- package/oveanet-pack/universal-backup/templates/backup-workflow.md +51 -0
- package/package.json +2 -1
- package/tools/cli/commands/install.js +38 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# SEO/GEO 360° Audit Checklist
|
|
2
|
+
|
|
3
|
+
## Usage
|
|
4
|
+
Use this checklist as a template for any website audit. Copy it to your project's output folder and check items as you go.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 1. Technical SEO
|
|
9
|
+
- [ ] `robots.txt` exists and is correctly configured
|
|
10
|
+
- [ ] `sitemap.xml` exists with all pages, `lastmod`, `changefreq`, `priority`
|
|
11
|
+
- [ ] Sitemap includes `xhtml:link` hreflang alternates (if multilingual)
|
|
12
|
+
- [ ] Canonical URLs present on all pages
|
|
13
|
+
- [ ] Hreflang tags for each language variant
|
|
14
|
+
- [ ] Meta robots: `index, follow, max-image-preview:large, max-snippet:-1`
|
|
15
|
+
- [ ] HTTPS enforced
|
|
16
|
+
- [ ] No render-blocking resources (fonts preloaded, CSS inlined or local)
|
|
17
|
+
- [ ] Mobile viewport meta tag present
|
|
18
|
+
- [ ] Favicon present (SVG preferred, fallback PNG)
|
|
19
|
+
- [ ] 404 error page exists
|
|
20
|
+
- [ ] Page load time < 3 seconds
|
|
21
|
+
|
|
22
|
+
## 2. On-Page SEO
|
|
23
|
+
- [ ] `<title>` tag: 50-60 chars, contains primary keyword, unique per page
|
|
24
|
+
- [ ] `<meta description>`: 150-160 chars, contains CTA, unique per page
|
|
25
|
+
- [ ] `<meta keywords>`: relevant long-tail keywords
|
|
26
|
+
- [ ] `<meta author>`: present
|
|
27
|
+
- [ ] Single `<h1>` per page, descriptive, keyword-rich
|
|
28
|
+
- [ ] Logical H2-H6 hierarchy
|
|
29
|
+
- [ ] Images: `alt` tags, `width`/`height`, `loading="lazy"`, WebP format
|
|
30
|
+
- [ ] Internal linking between pages
|
|
31
|
+
- [ ] External links: `rel="noopener"` on `target="_blank"`
|
|
32
|
+
- [ ] Content length adequate (300+ words for landing pages)
|
|
33
|
+
|
|
34
|
+
## 3. Schema.org / Structured Data
|
|
35
|
+
- [ ] Primary schema type (Organization/LocalBusiness/ProfessionalService)
|
|
36
|
+
- [ ] Service schema for each service offered
|
|
37
|
+
- [ ] FAQPage schema with real Q&As (minimum 5 questions)
|
|
38
|
+
- [ ] WebPage schema (datePublished, dateModified, inLanguage)
|
|
39
|
+
- [ ] BreadcrumbList schema
|
|
40
|
+
- [ ] Person schema for founder/team (if applicable)
|
|
41
|
+
- [ ] Review/AggregateRating schema (if applicable)
|
|
42
|
+
- [ ] Validated with Google Rich Results Test
|
|
43
|
+
|
|
44
|
+
## 4. GEO (Generative Engine Optimization)
|
|
45
|
+
- [ ] `llms.txt` file at site root with structured business info
|
|
46
|
+
- [ ] Content uses clear headings with question-based format
|
|
47
|
+
- [ ] FAQ section with expandable answers
|
|
48
|
+
- [ ] Concise, factual content per section (answers visible without interaction)
|
|
49
|
+
- [ ] AI crawlers allowed in `robots.txt`:
|
|
50
|
+
- [ ] GPTBot
|
|
51
|
+
- [ ] ChatGPT-User
|
|
52
|
+
- [ ] PerplexityBot
|
|
53
|
+
- [ ] ClaudeBot
|
|
54
|
+
- [ ] Google-Extended
|
|
55
|
+
- [ ] Content freshness: `dateModified` in schema, visible update dates
|
|
56
|
+
- [ ] E-E-A-T signals: author credentials, "About" info, LinkedIn links
|
|
57
|
+
- [ ] Tested queries in ChatGPT, Perplexity, and Gemini
|
|
58
|
+
|
|
59
|
+
## 5. Local SEO
|
|
60
|
+
- [ ] Geo meta tags: `geo.region`, `geo.placename`, `geo.position`, `ICBM`
|
|
61
|
+
- [ ] NAP (Name, Address, Phone/Email) in footer
|
|
62
|
+
- [ ] `<address>` HTML element used
|
|
63
|
+
- [ ] Schema includes `geo` (GeoCoordinates), `areaServed`, `address`
|
|
64
|
+
- [ ] Google Business Profile created and optimized
|
|
65
|
+
- [ ] Local keywords in title, description, and H1
|
|
66
|
+
- [ ] Citations on directories (Pages Jaunes, Google Maps, etc.)
|
|
67
|
+
|
|
68
|
+
## 6. Accessibility
|
|
69
|
+
- [ ] Skip navigation link
|
|
70
|
+
- [ ] `aria-hidden="true"` on decorative SVGs and elements
|
|
71
|
+
- [ ] `aria-label` on `<section>` and `<nav>` elements
|
|
72
|
+
- [ ] `aria-pressed` on toggle buttons
|
|
73
|
+
- [ ] Color contrast WCAG AA (4.5:1 minimum)
|
|
74
|
+
- [ ] Keyboard-navigable form elements
|
|
75
|
+
- [ ] `<html lang>` attribute set correctly (dynamic for multilingual)
|
|
76
|
+
- [ ] `prefers-reduced-motion` media query support
|
|
77
|
+
|
|
78
|
+
## 7. Social & Sharing
|
|
79
|
+
- [ ] Open Graph: `og:title`, `og:description`, `og:image`, `og:url`, `og:type`
|
|
80
|
+
- [ ] `og:site_name` present
|
|
81
|
+
- [ ] `og:locale` with `og:locale:alternate` for other languages
|
|
82
|
+
- [ ] `og:image` dimensions 1200×630px
|
|
83
|
+
- [ ] Twitter Card: `twitter:card` (summary_large_image)
|
|
84
|
+
- [ ] Social preview tested with sharing debugger tools
|
|
85
|
+
|
|
86
|
+
## 8. Multilingual SEO (if applicable)
|
|
87
|
+
- [ ] `<html lang>` dynamic based on selected language
|
|
88
|
+
- [ ] Bilingual `<title>` and `<meta description>` (via server-side logic)
|
|
89
|
+
- [ ] Hreflang tags for each page × each language
|
|
90
|
+
- [ ] `x-default` hreflang set
|
|
91
|
+
- [ ] Schema.org `description` in correct language
|
|
92
|
+
- [ ] OG tags in correct language (`og:locale`)
|
|
93
|
+
- [ ] Sitemap includes hreflang alternates per URL
|
|
94
|
+
- [ ] Language preference persisted (localStorage/cookie)
|
|
95
|
+
- [ ] Auto-detection of browser language (`navigator.language`)
|
|
96
|
+
- [ ] Legal pages (Privacy, Terms) translated
|
|
97
|
+
|
|
98
|
+
## 9. Content & Keywords
|
|
99
|
+
- [ ] Primary keyword identified per page
|
|
100
|
+
- [ ] Long-tail keyword variants in content
|
|
101
|
+
- [ ] Location-based keywords (city, region, country)
|
|
102
|
+
- [ ] Service-specific keywords
|
|
103
|
+
- [ ] Competitor keyword gap analysis
|
|
104
|
+
- [ ] Content matches search intent (informational, transactional, navigational)
|
|
105
|
+
|
|
106
|
+
## 10. PageSpeed 100% — Performance Perfection Loop
|
|
107
|
+
> Reference: See `pagespeed-playbook.md` for complete technique catalog with code examples.
|
|
108
|
+
|
|
109
|
+
### Performance (Impact-Ordered)
|
|
110
|
+
- [ ] Self-hosted fonts (woff2) — no Google CDN
|
|
111
|
+
- [ ] Font preload with `fetchpriority="high"` for critical weight
|
|
112
|
+
- [ ] `font-display: swap` on all `@font-face` rules
|
|
113
|
+
- [ ] ALL CSS inlined in production HTML (zero render-blocking)
|
|
114
|
+
- [ ] `.htaccess` cache headers: 1yr for static assets, 1hr for HTML
|
|
115
|
+
- [ ] Gzip/Brotli compression enabled (mod_deflate)
|
|
116
|
+
- [ ] ALL `<img>` tags have explicit `width` and `height` attributes
|
|
117
|
+
- [ ] Below-fold images have `loading="lazy"`
|
|
118
|
+
- [ ] LCP image has `fetchpriority="high"`
|
|
119
|
+
- [ ] Third-party scripts use `async defer`
|
|
120
|
+
- [ ] CLS = 0 (no layout shifts during load)
|
|
121
|
+
|
|
122
|
+
### Accessibility (WCAG AA)
|
|
123
|
+
- [ ] ALL text/background combos ≥ 4.5:1 contrast ratio
|
|
124
|
+
- [ ] White text on orange backgrounds replaced with dark text (#1a0800)
|
|
125
|
+
- [ ] Dim/muted text on dark backgrounds brightened to ≥ #a0b0b8
|
|
126
|
+
- [ ] Badge text with transparency backgrounds ≥ #d4dde3
|
|
127
|
+
- [ ] Checked: CTA buttons, active nav states, badges, footer, form labels, tags
|
|
128
|
+
|
|
129
|
+
### Best Practices
|
|
130
|
+
- [ ] No console errors from own code
|
|
131
|
+
- [ ] Third-party console errors documented as known limitations
|
|
132
|
+
- [ ] All external links have `rel="noopener noreferrer"`
|
|
133
|
+
- [ ] All resources loaded over HTTPS
|
|
134
|
+
|
|
135
|
+
### Anti-Patterns (NEVER DO)
|
|
136
|
+
- [ ] ❌ Never use `media="print" onload` for CSS (causes CLS 0.936)
|
|
137
|
+
- [ ] ❌ Never load fonts from external CDN without local fallback
|
|
138
|
+
- [ ] ❌ Never leave `<img>` tags without width/height dimensions
|
|
139
|
+
- [ ] ❌ Never fix contrast issues one at a time (batch ALL at once)
|
|
140
|
+
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
# 🎯 PageSpeed Perfection Playbook — Battle-Tested Guide
|
|
2
|
+
|
|
3
|
+
> **Version 1.0.0** — Based on 6+ real-world iterations achieving 99-100% on oveanet.ch, montpellier.ai, and oveanet.fr
|
|
4
|
+
> By Laurent ROCHETTA × AI
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## 📐 Architecture: The 4-Phase Protocol
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
Phase 1: DIAGNOSTIC → Extract scores, identify all failing audits
|
|
12
|
+
Phase 2: PERFORMANCE → Self-host fonts → Inline CSS → Cache → CLS
|
|
13
|
+
Phase 3: ACCESSIBILITY → WCAG AA contrast fixes (systematic)
|
|
14
|
+
Phase 4: BEST PRACTICES & SEO → Console errors, security, meta tags
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Each phase runs sequentially. **Backup before each phase.** Re-test after each phase.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## ⚠️ Anti-Patterns — Things That BREAK Scores
|
|
22
|
+
|
|
23
|
+
> [!CAUTION]
|
|
24
|
+
> These are real mistakes made during optimization that caused score REGRESSIONS.
|
|
25
|
+
|
|
26
|
+
### 🔴 NEVER: Async CSS Loading
|
|
27
|
+
```html
|
|
28
|
+
<!-- ❌ DISASTER — causes CLS 0.936 on mobile -->
|
|
29
|
+
<link rel="stylesheet" href="styles.css" media="print" onload="this.media='all'"/>
|
|
30
|
+
<noscript><link rel="stylesheet" href="styles.css"/></noscript>
|
|
31
|
+
```
|
|
32
|
+
**What happens:** The page renders with no styles, then FLASHES when CSS loads. PageSpeed measures this as a massive Cumulative Layout Shift (0.936 — nearly maximum). Performance dropped from 86 to 75.
|
|
33
|
+
|
|
34
|
+
**Fix:** Either load CSS synchronously or inline it entirely.
|
|
35
|
+
|
|
36
|
+
### 🔴 NEVER: External Font CDN Without Fallback
|
|
37
|
+
```html
|
|
38
|
+
<!-- ❌ Adds 300-800ms to LCP on mobile 4G -->
|
|
39
|
+
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600;700" rel="stylesheet"/>
|
|
40
|
+
```
|
|
41
|
+
**What happens:** DNS lookup + TLS handshake to `fonts.googleapis.com`, then another to `fonts.gstatic.com`. On 4G simulation, this adds 500ms+ to LCP.
|
|
42
|
+
|
|
43
|
+
### 🔴 NEVER: Images Without Dimensions
|
|
44
|
+
```html
|
|
45
|
+
<!-- ❌ Causes CLS because browser doesn't know the space to reserve -->
|
|
46
|
+
<img src="logo.svg" alt="Logo"/>
|
|
47
|
+
```
|
|
48
|
+
**Fix:** Always add `width` and `height`:
|
|
49
|
+
```html
|
|
50
|
+
<img src="logo.svg" alt="Logo" width="100" height="20"/>
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 🏆 Technique Catalog — Ordered by Impact
|
|
56
|
+
|
|
57
|
+
### [P1] Self-Host Fonts (Biggest LCP Win)
|
|
58
|
+
|
|
59
|
+
**Impact:** LCP -30-50% on mobile, eliminates 2 external requests
|
|
60
|
+
|
|
61
|
+
**Step 1:** Download fonts from Google Fonts API or copy from existing projects:
|
|
62
|
+
```
|
|
63
|
+
fonts/
|
|
64
|
+
├── space-grotesk-400-latin.woff2
|
|
65
|
+
├── space-grotesk-600-latin.woff2
|
|
66
|
+
└── space-grotesk-700-latin.woff2
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Step 2:** Update CSS `@font-face` declarations:
|
|
70
|
+
```css
|
|
71
|
+
/* ✅ Self-hosted — zero external requests */
|
|
72
|
+
@font-face {
|
|
73
|
+
font-family: 'Space Grotesk';
|
|
74
|
+
font-style: normal;
|
|
75
|
+
font-weight: 400;
|
|
76
|
+
font-display: swap;
|
|
77
|
+
src: url('fonts/space-grotesk-400-latin.woff2') format('woff2');
|
|
78
|
+
}
|
|
79
|
+
@font-face {
|
|
80
|
+
font-family: 'Space Grotesk';
|
|
81
|
+
font-style: normal;
|
|
82
|
+
font-weight: 600;
|
|
83
|
+
font-display: swap;
|
|
84
|
+
src: url('fonts/space-grotesk-600-latin.woff2') format('woff2');
|
|
85
|
+
}
|
|
86
|
+
@font-face {
|
|
87
|
+
font-family: 'Space Grotesk';
|
|
88
|
+
font-style: normal;
|
|
89
|
+
font-weight: 700;
|
|
90
|
+
font-display: swap;
|
|
91
|
+
src: url('fonts/space-grotesk-700-latin.woff2') format('woff2');
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Step 3:** Preload critical fonts in HTML `<head>`:
|
|
96
|
+
```html
|
|
97
|
+
<link rel="preload" href="fonts/space-grotesk-400-latin.woff2"
|
|
98
|
+
as="font" type="font/woff2" crossorigin fetchpriority="high"/>
|
|
99
|
+
<link rel="preload" href="fonts/space-grotesk-600-latin.woff2"
|
|
100
|
+
as="font" type="font/woff2" crossorigin/>
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Step 4:** Remove ALL Google Fonts CDN references:
|
|
104
|
+
```diff
|
|
105
|
+
-<link rel="preconnect" href="https://fonts.googleapis.com"/>
|
|
106
|
+
-<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/>
|
|
107
|
+
-<link href="https://fonts.googleapis.com/css2?..." rel="stylesheet"/>
|
|
108
|
+
+<!-- Fonts are self-hosted, no external CDN needed -->
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### How to get woff2 files from Google Fonts:
|
|
112
|
+
```bash
|
|
113
|
+
# Method 1: Use google-webfonts-helper
|
|
114
|
+
# https://gwfh.mranftl.com/fonts
|
|
115
|
+
|
|
116
|
+
# Method 2: Direct download with curl (set woff2 user-agent)
|
|
117
|
+
curl -H "User-Agent: Mozilla/5.0" \
|
|
118
|
+
"https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;600;700&display=swap" \
|
|
119
|
+
| grep -oP 'url\(\K[^)]+' | while read url; do
|
|
120
|
+
wget "$url" -P fonts/
|
|
121
|
+
done
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### [P2] Inline ALL CSS (Zero Render-Blocking)
|
|
127
|
+
|
|
128
|
+
**Impact:** Eliminates render-blocking CSS request, reduces FCP by 100-300ms
|
|
129
|
+
|
|
130
|
+
**For PHP sites** (like montpellier.ai):
|
|
131
|
+
```php
|
|
132
|
+
<!-- ✅ CSS inlined at build time — zero render-blocking -->
|
|
133
|
+
<style><?php echo file_get_contents(__DIR__ . '/styles.css'); ?></style>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**For static HTML sites** (build script):
|
|
137
|
+
|
|
138
|
+
PowerShell build script:
|
|
139
|
+
```powershell
|
|
140
|
+
# build-dist.ps1 — Inline CSS into HTML for production
|
|
141
|
+
$css = Get-Content "styles.css" -Raw
|
|
142
|
+
$html = Get-Content "index.html" -Raw
|
|
143
|
+
|
|
144
|
+
$cssInline = " <style>`n$css`n </style>"
|
|
145
|
+
|
|
146
|
+
# Replace the critical CSS + external link with full inline
|
|
147
|
+
$pattern = ' <!-- Critical CSS.*?</style>\s*\r?\n.*?<link rel="stylesheet" href="styles.css"/>'
|
|
148
|
+
$html = $html -replace $pattern, $cssInline
|
|
149
|
+
|
|
150
|
+
$html | Set-Content "dist/index.html" -Encoding UTF8
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Bash build script:
|
|
154
|
+
```bash
|
|
155
|
+
#!/bin/bash
|
|
156
|
+
# build-dist.sh — Inline CSS into HTML for production
|
|
157
|
+
CSS=$(cat styles.css)
|
|
158
|
+
sed -e '/<!-- Critical CSS/,/<link rel="stylesheet"/c\ <style>'"$CSS"'</style>' \
|
|
159
|
+
index.html > dist/index.html
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
> [!IMPORTANT]
|
|
163
|
+
> Keep source files separate (index.html + styles.css) for development.
|
|
164
|
+
> Only the dist/ version gets the inlined CSS for production.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
### [P3] Cache Headers (.htaccess Template)
|
|
169
|
+
|
|
170
|
+
**Impact:** Fixes "Use efficient cache policy" audit
|
|
171
|
+
|
|
172
|
+
```apache
|
|
173
|
+
# === PageSpeed Cache & Compression — Ready to Deploy ===
|
|
174
|
+
|
|
175
|
+
<IfModule mod_expires.c>
|
|
176
|
+
ExpiresActive On
|
|
177
|
+
ExpiresDefault "access plus 1 month"
|
|
178
|
+
ExpiresByType text/html "access plus 1 hour"
|
|
179
|
+
ExpiresByType text/css "access plus 1 year"
|
|
180
|
+
ExpiresByType application/javascript "access plus 1 year"
|
|
181
|
+
ExpiresByType image/svg+xml "access plus 1 year"
|
|
182
|
+
ExpiresByType image/png "access plus 1 year"
|
|
183
|
+
ExpiresByType image/webp "access plus 1 year"
|
|
184
|
+
ExpiresByType font/woff2 "access plus 1 year"
|
|
185
|
+
ExpiresByType application/font-woff2 "access plus 1 year"
|
|
186
|
+
</IfModule>
|
|
187
|
+
|
|
188
|
+
<IfModule mod_headers.c>
|
|
189
|
+
<FilesMatch "\.(css|js|svg|png|webp|woff2|ico)$">
|
|
190
|
+
Header set Cache-Control "public, max-age=31536000, immutable"
|
|
191
|
+
</FilesMatch>
|
|
192
|
+
<FilesMatch "\.(html|php)$">
|
|
193
|
+
Header set Cache-Control "public, max-age=3600, must-revalidate"
|
|
194
|
+
</FilesMatch>
|
|
195
|
+
<FilesMatch "\.(txt|xml)$">
|
|
196
|
+
Header set Cache-Control "public, max-age=86400"
|
|
197
|
+
</FilesMatch>
|
|
198
|
+
</IfModule>
|
|
199
|
+
|
|
200
|
+
# Gzip Compression
|
|
201
|
+
<IfModule mod_deflate.c>
|
|
202
|
+
AddOutputFilterByType DEFLATE text/html text/css application/javascript
|
|
203
|
+
AddOutputFilterByType DEFLATE text/javascript application/json text/xml
|
|
204
|
+
AddOutputFilterByType DEFLATE image/svg+xml text/plain
|
|
205
|
+
</IfModule>
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
### [P4] CLS Prevention Checklist
|
|
211
|
+
|
|
212
|
+
| Element | Required Fix |
|
|
213
|
+
|---------|-------------|
|
|
214
|
+
| `<img>` tags | Add `width` and `height` attributes |
|
|
215
|
+
| CSS-loaded fonts | Use `font-display: swap` |
|
|
216
|
+
| CSS loading | NEVER use `media="print" onload` trick |
|
|
217
|
+
| Dynamic content | Reserve space with min-height |
|
|
218
|
+
| Embeds/iframes | Set explicit dimensions |
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## 🎨 Accessibility — Contrast Ratio Reference
|
|
223
|
+
|
|
224
|
+
### The Rule
|
|
225
|
+
WCAG AA requires **4.5:1** contrast ratio for normal text, **3:1** for large text (18px+ or 14px+ bold).
|
|
226
|
+
|
|
227
|
+
### Common Color Combos on Dark Backgrounds (#0B0C15)
|
|
228
|
+
|
|
229
|
+
| Text Color | Hex | Ratio vs #0B0C15 | Pass? |
|
|
230
|
+
|-----------|-----|:-----------------:|:-----:|
|
|
231
|
+
| Pure white | `#ffffff` | 19.2:1 | ✅ |
|
|
232
|
+
| Light gray | `#d4dde3` | 12.5:1 | ✅ |
|
|
233
|
+
| Medium gray | `#a0b0b8` | 6.5:1 | ✅ |
|
|
234
|
+
| Muted gray | `#b0bec5` | 8.0:1 | ✅ |
|
|
235
|
+
| Dim gray | `#6b7b8a` | 3.7:1 | ❌ |
|
|
236
|
+
| Very dim | `#4a5568` | 2.3:1 | ❌ |
|
|
237
|
+
|
|
238
|
+
### Common Color Combos on Orange (#E8632B)
|
|
239
|
+
|
|
240
|
+
| Text Color | Hex | Ratio vs #E8632B | Pass? |
|
|
241
|
+
|-----------|-----|:-----------------:|:-----:|
|
|
242
|
+
| White | `#ffffff` | 3.3:1 | ❌ FAIL |
|
|
243
|
+
| Light cream | `#fff5e6` | 3.1:1 | ❌ FAIL |
|
|
244
|
+
| Dark brown | `#1a0800` | 8.5:1 | ✅ |
|
|
245
|
+
| Black | `#000000` | 4.0:1 | ✅ (large) |
|
|
246
|
+
|
|
247
|
+
> [!WARNING]
|
|
248
|
+
> **White text on orange buttons is a classic fail.** Ratio is only 3.3:1.
|
|
249
|
+
> Use dark text (`#1a0800`) instead for buttons, badges, and active states with orange backgrounds.
|
|
250
|
+
|
|
251
|
+
### Elements Commonly Flagged by PageSpeed
|
|
252
|
+
1. **CTA buttons** (`.btn-primary`) — white on primary color
|
|
253
|
+
2. **Active language buttons** (`.lang-btn.active`) — white on primary
|
|
254
|
+
3. **Pricing badges** ("Most Popular") — white on primary
|
|
255
|
+
4. **Footer text** — dim on very dark background
|
|
256
|
+
5. **Form labels** — muted on dark
|
|
257
|
+
6. **Badge text** (partner badges, sponsor badges) — muted on dark with transparency
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## 📊 Score Tracking Template
|
|
262
|
+
|
|
263
|
+
```markdown
|
|
264
|
+
| Iteration | Perf (M) | A11y (M) | Perf (D) | A11y (D) | BP | SEO | Changes |
|
|
265
|
+
|:---------:|:--------:|:--------:|:--------:|:--------:|:---:|:---:|---------|
|
|
266
|
+
| Baseline | ? | ? | ? | ? | ? | ? | Initial |
|
|
267
|
+
| #1 | | | | | | | |
|
|
268
|
+
| #2 | | | | | | | |
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## 🔧 PageSpeed JavaScript Extraction Snippets
|
|
274
|
+
|
|
275
|
+
Use these in the browser to extract structured data from PageSpeed results:
|
|
276
|
+
|
|
277
|
+
### Extract All Scores
|
|
278
|
+
```javascript
|
|
279
|
+
JSON.stringify({
|
|
280
|
+
gauges: Array.from(document.querySelectorAll('.lh-gauge__percentage'))
|
|
281
|
+
.map(g => g.textContent.trim()),
|
|
282
|
+
labels: Array.from(document.querySelectorAll('.lh-gauge__label'))
|
|
283
|
+
.map(l => l.textContent.trim())
|
|
284
|
+
});
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Extract Core Web Vitals
|
|
288
|
+
```javascript
|
|
289
|
+
JSON.stringify({
|
|
290
|
+
metrics: Array.from(document.querySelectorAll('.lh-metric'))
|
|
291
|
+
.map(m => ({
|
|
292
|
+
name: m.querySelector('.lh-metric__title')?.textContent?.trim(),
|
|
293
|
+
value: m.querySelector('.lh-metric__value')?.textContent?.trim()
|
|
294
|
+
}))
|
|
295
|
+
});
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### Extract Failing Audits
|
|
299
|
+
```javascript
|
|
300
|
+
JSON.stringify({
|
|
301
|
+
failed: Array.from(document.querySelectorAll('.lh-audit--fail .lh-audit__title'))
|
|
302
|
+
.map(a => a.textContent.trim().substring(0, 150)),
|
|
303
|
+
warnings: Array.from(document.querySelectorAll('.lh-audit--average .lh-audit__title'))
|
|
304
|
+
.map(a => a.textContent.trim().substring(0, 150))
|
|
305
|
+
});
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## 🏁 Exit Conditions
|
|
311
|
+
|
|
312
|
+
The PageSpeed Perfection Loop STOPS when:
|
|
313
|
+
- ✅ **ALL 4 scores = 100/100** → Perfection achieved
|
|
314
|
+
- ⚠️ **After 8 iterations** → Report remaining issues with root cause analysis
|
|
315
|
+
- 🟡 **Only server-side issues remain** (TTFB, CDN, HTTP/2) → Report as "requires server-side changes"
|
|
316
|
+
- 🟡 **Only third-party script issues remain** (Cloudflare Turnstile, analytics) → Report as "not fixable client-side"
|
|
317
|
+
|
|
318
|
+
---
|
|
319
|
+
|
|
320
|
+
*Built with ❤️ in Montpellier, France — by Laurent ROCHETTA × AI*
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# TEMPLATE — llms.txt
|
|
2
|
+
# Replace [BRACKETS] with your actual information
|
|
3
|
+
|
|
4
|
+
# [Your Company Name]
|
|
5
|
+
|
|
6
|
+
> [One-line elevator pitch describing your company]
|
|
7
|
+
|
|
8
|
+
## About
|
|
9
|
+
|
|
10
|
+
[Company Name] is a [type of company] based in [City, Country]. [2-3 sentences describing what you do, your unique value proposition, and your target audience.]
|
|
11
|
+
|
|
12
|
+
Founded by [Founder Name], the company specializes in [core specializations].
|
|
13
|
+
|
|
14
|
+
## Services
|
|
15
|
+
|
|
16
|
+
### [Service 1 Name]
|
|
17
|
+
- [Key feature 1]
|
|
18
|
+
- [Key feature 2]
|
|
19
|
+
- [Key feature 3]
|
|
20
|
+
|
|
21
|
+
### [Service 2 Name]
|
|
22
|
+
- [Key feature 1]
|
|
23
|
+
- [Key feature 2]
|
|
24
|
+
- [Key feature 3]
|
|
25
|
+
|
|
26
|
+
### [Service 3 Name]
|
|
27
|
+
- [Key feature 1]
|
|
28
|
+
- [Key feature 2]
|
|
29
|
+
- [Key feature 3]
|
|
30
|
+
|
|
31
|
+
## Methodology
|
|
32
|
+
|
|
33
|
+
1. **[Phase 1 Name]**: [Brief description]
|
|
34
|
+
2. **[Phase 2 Name]**: [Brief description]
|
|
35
|
+
3. **[Phase 3 Name]**: [Brief description]
|
|
36
|
+
|
|
37
|
+
## Unique Value Proposition
|
|
38
|
+
|
|
39
|
+
- **[USP 1]**: [Brief description]
|
|
40
|
+
- **[USP 2]**: [Brief description]
|
|
41
|
+
- **[USP 3]**: [Brief description]
|
|
42
|
+
|
|
43
|
+
## FAQ
|
|
44
|
+
|
|
45
|
+
### [Question 1]?
|
|
46
|
+
[Concise, factual answer — 2-3 sentences max]
|
|
47
|
+
|
|
48
|
+
### [Question 2]?
|
|
49
|
+
[Concise, factual answer]
|
|
50
|
+
|
|
51
|
+
### [Question 3]?
|
|
52
|
+
[Concise, factual answer]
|
|
53
|
+
|
|
54
|
+
### [Question 4]?
|
|
55
|
+
[Concise, factual answer]
|
|
56
|
+
|
|
57
|
+
### [Question 5]?
|
|
58
|
+
[Concise, factual answer]
|
|
59
|
+
|
|
60
|
+
### [Question 6]?
|
|
61
|
+
[Concise, factual answer]
|
|
62
|
+
|
|
63
|
+
## Contact
|
|
64
|
+
|
|
65
|
+
- **Website**: https://[your-domain.com]
|
|
66
|
+
- **Email**: [contact@your-domain.com]
|
|
67
|
+
- **LinkedIn**: [LinkedIn URL]
|
|
68
|
+
- **Location**: [City, Country (Postal Code)]
|
|
69
|
+
|
|
70
|
+
## Legal
|
|
71
|
+
|
|
72
|
+
- [Privacy Policy](https://[your-domain.com]/privacy)
|
|
73
|
+
- [Terms of Service](https://[your-domain.com]/terms)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# TEMPLATE — robots.txt
|
|
2
|
+
# Adapt domain and sitemap URL to your project
|
|
3
|
+
|
|
4
|
+
User-agent: *
|
|
5
|
+
Allow: /
|
|
6
|
+
Sitemap: https://YOUR-DOMAIN.com/sitemap.xml
|
|
7
|
+
|
|
8
|
+
# AI Crawlers (GEO optimization — allow all)
|
|
9
|
+
User-agent: GPTBot
|
|
10
|
+
Allow: /
|
|
11
|
+
|
|
12
|
+
User-agent: ChatGPT-User
|
|
13
|
+
Allow: /
|
|
14
|
+
|
|
15
|
+
User-agent: PerplexityBot
|
|
16
|
+
Allow: /
|
|
17
|
+
|
|
18
|
+
User-agent: ClaudeBot
|
|
19
|
+
Allow: /
|
|
20
|
+
|
|
21
|
+
User-agent: Google-Extended
|
|
22
|
+
Allow: /
|
|
23
|
+
|
|
24
|
+
User-agent: Googlebot
|
|
25
|
+
Allow: /
|
|
26
|
+
|
|
27
|
+
User-agent: Bingbot
|
|
28
|
+
Allow: /
|
|
29
|
+
|
|
30
|
+
# Block known scraper bots (optional)
|
|
31
|
+
User-agent: AhrefsBot
|
|
32
|
+
Disallow: /
|
|
33
|
+
|
|
34
|
+
User-agent: SemrushBot
|
|
35
|
+
Disallow: /
|
|
36
|
+
|
|
37
|
+
User-agent: MJ12bot
|
|
38
|
+
Disallow: /
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "TEMPLATE — Schema.org JSON-LD Templates for SEO/GEO Optimization",
|
|
3
|
+
"_instructions": "Copy the relevant schema types into your page's <head> as <script type='application/ld+json'>. Replace [BRACKETS] with actual values.",
|
|
4
|
+
|
|
5
|
+
"ProfessionalService": {
|
|
6
|
+
"@context": "https://schema.org",
|
|
7
|
+
"@type": "ProfessionalService",
|
|
8
|
+
"name": "[Company Name]",
|
|
9
|
+
"url": "https://[your-domain.com]",
|
|
10
|
+
"logo": "https://[your-domain.com]/logo.svg",
|
|
11
|
+
"image": "https://[your-domain.com]/og.jpg",
|
|
12
|
+
"description": "[Company description — 1-2 sentences]",
|
|
13
|
+
"founder": {
|
|
14
|
+
"@type": "Person",
|
|
15
|
+
"name": "[Founder Name]",
|
|
16
|
+
"url": "[Founder LinkedIn URL]"
|
|
17
|
+
},
|
|
18
|
+
"sameAs": ["[LinkedIn URL]", "[Twitter URL]", "[GitHub URL]"],
|
|
19
|
+
"address": {
|
|
20
|
+
"@type": "PostalAddress",
|
|
21
|
+
"addressLocality": "[City]",
|
|
22
|
+
"postalCode": "[Postal Code]",
|
|
23
|
+
"addressRegion": "[Region]",
|
|
24
|
+
"addressCountry": "[Country Code]"
|
|
25
|
+
},
|
|
26
|
+
"geo": {
|
|
27
|
+
"@type": "GeoCoordinates",
|
|
28
|
+
"latitude": 0.0,
|
|
29
|
+
"longitude": 0.0
|
|
30
|
+
},
|
|
31
|
+
"areaServed": [
|
|
32
|
+
{ "@type": "Country", "name": "[Country]" },
|
|
33
|
+
{ "@type": "Place", "name": "International" }
|
|
34
|
+
],
|
|
35
|
+
"knowsAbout": ["[Skill 1]", "[Skill 2]", "[Skill 3]"],
|
|
36
|
+
"hasOfferCatalog": {
|
|
37
|
+
"@type": "OfferCatalog",
|
|
38
|
+
"name": "Services",
|
|
39
|
+
"itemListElement": [
|
|
40
|
+
{
|
|
41
|
+
"@type": "Offer",
|
|
42
|
+
"itemOffered": {
|
|
43
|
+
"@type": "Service",
|
|
44
|
+
"name": "[Service 1]",
|
|
45
|
+
"description": "[Service 1 description]"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
"@type": "Offer",
|
|
50
|
+
"itemOffered": {
|
|
51
|
+
"@type": "Service",
|
|
52
|
+
"name": "[Service 2]",
|
|
53
|
+
"description": "[Service 2 description]"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
"FAQPage": {
|
|
61
|
+
"@context": "https://schema.org",
|
|
62
|
+
"@type": "FAQPage",
|
|
63
|
+
"mainEntity": [
|
|
64
|
+
{
|
|
65
|
+
"@type": "Question",
|
|
66
|
+
"name": "[Question 1]?",
|
|
67
|
+
"acceptedAnswer": {
|
|
68
|
+
"@type": "Answer",
|
|
69
|
+
"text": "[Answer 1]"
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"@type": "Question",
|
|
74
|
+
"name": "[Question 2]?",
|
|
75
|
+
"acceptedAnswer": {
|
|
76
|
+
"@type": "Answer",
|
|
77
|
+
"text": "[Answer 2]"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
"WebPage": {
|
|
84
|
+
"@context": "https://schema.org",
|
|
85
|
+
"@type": "WebPage",
|
|
86
|
+
"name": "[Page Title]",
|
|
87
|
+
"url": "https://[your-domain.com]/",
|
|
88
|
+
"datePublished": "[YYYY-MM-DD]",
|
|
89
|
+
"dateModified": "[YYYY-MM-DD]",
|
|
90
|
+
"inLanguage": ["en", "fr"],
|
|
91
|
+
"isPartOf": {
|
|
92
|
+
"@type": "WebSite",
|
|
93
|
+
"name": "[Site Name]",
|
|
94
|
+
"url": "https://[your-domain.com]/"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
"BreadcrumbList": {
|
|
99
|
+
"@context": "https://schema.org",
|
|
100
|
+
"@type": "BreadcrumbList",
|
|
101
|
+
"itemListElement": [
|
|
102
|
+
{
|
|
103
|
+
"@type": "ListItem",
|
|
104
|
+
"position": 1,
|
|
105
|
+
"name": "Home",
|
|
106
|
+
"item": "https://[your-domain.com]/"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"@type": "ListItem",
|
|
110
|
+
"position": 2,
|
|
111
|
+
"name": "[Page Name]",
|
|
112
|
+
"item": "https://[your-domain.com]/[page]"
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
}
|