/SKILL.md
# SKILL.md — Compétences Web Frontend **Skills spécialisées pour l'agent Claude Web** --- ## 🎨 Design & UI/UX ### Responsive Design **Niveau** : Expert **Capacités** : - Mobile-first design approach - Breakpoints Tailwind : `sm:`, `md:`, `lg:`, `xl:`, `2xl:` - Layouts adaptatifs (Grid, Flexbox) - Images responsives (`srcset`, `sizes`) - Typography fluide (`clamp()`) **Exemples** : ```html <!-- Grid responsive --> <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <div>Ca
npx skillsauth add labsmates/claude-web claude-webInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Skills spécialisées pour l'agent Claude Web
Niveau : Expert
Capacités :
sm:, md:, lg:, xl:, 2xl:srcset, sizes)clamp())Exemples :
<!-- Grid responsive -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div>Card 1</div>
<div>Card 2</div>
<div>Card 3</div>
</div>
<!-- Typography fluide -->
<h1 class="text-4xl md:text-5xl lg:text-6xl">Titre</h1>
Niveau : Expert
Capacités :
tailwind.config.js)[color:#custom])Configuration type :
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
brand: {
50: '#f0f9ff',
500: '#0ea5e9',
900: '#0c4a6e'
}
},
fontFamily: {
display: ['Inter', 'sans-serif'],
body: ['Open Sans', 'sans-serif']
}
}
},
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/typography')
]
}
Niveau : Avancé
CSS Animations :
/* Keyframes custom */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.animate-fade-in-up {
animation: fadeInUp 0.6s ease-out;
}
JavaScript Animations (GSAP) :
// Animation au scroll
gsap.from('.card', {
scrollTrigger: '.card',
y: 100,
opacity: 0,
duration: 0.8,
stagger: 0.2
});
Transitions Tailwind :
<button class="transform transition-all duration-300 hover:scale-105 hover:shadow-lg">
Hover moi
</button>
Niveau : Avancé
Spacing Scale :
// Système d'espacement cohérent
const spacing = {
xs: '0.5rem', // 8px
sm: '1rem', // 16px
md: '1.5rem', // 24px
lg: '2rem', // 32px
xl: '3rem', // 48px
'2xl': '4rem' // 64px
};
Color Palette :
// Palette cohérente (60-30-10 rule)
primary: 60% // Couleur dominante
secondary: 30% // Couleur d'accent
accent: 10% // Highlights
Niveau : Expert
Fonctionnalités modernes :
// Arrow functions
const double = (x) => x * 2;
// Destructuring
const { name, age } = user;
const [first, ...rest] = array;
// Template literals
const message = `Bonjour ${name}`;
// Modules
import { feature } from './module.js';
export default MyComponent;
// Async/Await
async function fetchData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} catch (error) {
console.error(error);
}
}
// Array methods
const filtered = items.filter(item => item.active);
const mapped = items.map(item => item.name);
const reduced = items.reduce((sum, item) => sum + item.price, 0);
Niveau : Expert
// Sélection
const element = document.querySelector('.my-class');
const elements = document.querySelectorAll('.items');
// Création
const div = document.createElement('div');
div.classList.add('card', 'shadow');
div.innerHTML = '<h2>Titre</h2>';
document.body.appendChild(div);
// Event listeners
element.addEventListener('click', (e) => {
e.preventDefault();
console.log('Clicked!');
});
// Classes
element.classList.add('active');
element.classList.remove('hidden');
element.classList.toggle('open');
// Attributes
element.setAttribute('data-id', '123');
const id = element.getAttribute('data-id');
// Styles
element.style.backgroundColor = '#f0f0f0';
Niveau : Avancé
// Fetch moderne
async function getData() {
try {
const response = await fetch('https://api.example.com/data', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token'
}
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Fetch error:', error);
throw error;
}
}
// POST request
async function postData(payload) {
const response = await fetch('/api/submit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
return response.json();
}
Niveau : Avancé
HTML Sémantique :
<header>
<nav aria-label="Navigation principale">
<ul>
<li><a href="#home">Accueil</a></li>
</ul>
</nav>
</header>
<main>
<article>
<h1>Titre principal</h1>
<p>Contenu...</p>
</article>
</main>
<footer>
<p>© 2026</p>
</footer>
ARIA Attributes :
<!-- Button toggle -->
<button
aria-pressed="false"
aria-label="Ouvrir le menu"
id="menu-toggle">
Menu
</button>
<!-- Modal -->
<div
role="dialog"
aria-labelledby="modal-title"
aria-modal="true">
<h2 id="modal-title">Titre Modal</h2>
</div>
<!-- Live region -->
<div aria-live="polite" aria-atomic="true">
Message de confirmation
</div>
Navigation clavier :
// Trap focus dans modal
function trapFocus(element) {
const focusableElements = element.querySelectorAll(
'a, button, input, textarea, select, [tabindex]:not([tabindex="-1"])'
);
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
element.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === firstElement) {
e.preventDefault();
lastElement.focus();
} else if (!e.shiftKey && document.activeElement === lastElement) {
e.preventDefault();
firstElement.focus();
}
}
});
}
Niveau : Avancé
<!-- Responsive images -->
<img
srcset="image-320w.jpg 320w,
image-640w.jpg 640w,
image-1280w.jpg 1280w"
sizes="(max-width: 640px) 100vw,
(max-width: 1024px) 50vw,
33vw"
src="image-640w.jpg"
alt="Description"
loading="lazy">
<!-- WebP avec fallback -->
<picture>
<source srcset="image.webp" type="image/webp">
<source srcset="image.jpg" type="image/jpeg">
<img src="image.jpg" alt="Description">
</picture>
Niveau : Avancé
// Intersection Observer
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => {
observer.observe(img);
});
Niveau : Intermédiaire
// Dynamic import
async function loadModule() {
const module = await import('./heavy-module.js');
module.init();
}
// Charger au clic
button.addEventListener('click', async () => {
const { feature } = await import('./feature.js');
feature();
});
Niveau : Avancé
<head>
<!-- Essential -->
<title>Titre de la page (50-60 caractères)</title>
<meta name="description" content="Description (150-160 caractères)">
<!-- Open Graph (Facebook, LinkedIn) -->
<meta property="og:title" content="Titre">
<meta property="og:description" content="Description">
<meta property="og:image" content="https://example.com/image.jpg">
<meta property="og:url" content="https://example.com">
<meta property="og:type" content="website">
<!-- Twitter Card -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Titre">
<meta name="twitter:description" content="Description">
<meta name="twitter:image" content="https://example.com/image.jpg">
<!-- Viewport & Charset -->
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Canonical -->
<link rel="canonical" href="https://example.com/page">
</head>
Niveau : Intermédiaire
<!-- Schema.org JSON-LD -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Organization",
"name": "Mon Entreprise",
"url": "https://example.com",
"logo": "https://example.com/logo.png",
"contactPoint": {
"@type": "ContactPoint",
"telephone": "+33-1-23-45-67-89",
"contactType": "Customer Service"
}
}
</script>
Niveau : Expert
Raccourcis utiles :
Ctrl+Shift+C : Inspecteur d'élémentCtrl+Shift+J : ConsoleCtrl+Shift+M : Mode responsiveF12 : Ouvrir DevToolsConsole tricks :
// Mesurer performance
console.time('operation');
// ... code ...
console.timeEnd('operation');
// Tableaux
console.table([{name: 'Alice', age: 30}, {name: 'Bob', age: 25}]);
// Groupes
console.group('User Details');
console.log('Name:', user.name);
console.log('Age:', user.age);
console.groupEnd();
Niveau : Avancé
Critères :
Optimisations courantes :
{
"frameworks": ["Tailwind CSS", "Alpine.js (optionnel)"],
"animations": ["GSAP", "Anime.js", "Framer Motion"],
"icons": ["Heroicons", "Feather Icons", "Lucide"],
"charts": ["Chart.js", "D3.js", "ApexCharts"],
"forms": ["Parsley.js", "Validator.js"],
"utilities": ["Day.js", "Lodash (ES)", "UUID"]
}
function openModal(modalId) {
const modal = document.getElementById(modalId);
modal.classList.remove('hidden');
document.body.style.overflow = 'hidden';
trapFocus(modal);
// Fermer au clic backdrop
modal.addEventListener('click', (e) => {
if (e.target === modal) closeModal(modalId);
});
// Fermer à Escape
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') closeModal(modalId);
});
}
function closeModal(modalId) {
const modal = document.getElementById(modalId);
modal.classList.add('hidden');
document.body.style.overflow = '';
}
function validateForm(formId) {
const form = document.getElementById(formId);
const inputs = form.querySelectorAll('input[required]');
let isValid = true;
inputs.forEach(input => {
if (!input.value.trim()) {
input.classList.add('border-red-500');
isValid = false;
} else {
input.classList.remove('border-red-500');
}
});
return isValid;
}
// Usage
form.addEventListener('submit', (e) => {
e.preventDefault();
if (validateForm('my-form')) {
// Submit form
}
});
let page = 1;
let loading = false;
window.addEventListener('scroll', async () => {
if (loading) return;
const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight - 100) {
loading = true;
page++;
const newItems = await fetchItems(page);
appendItems(newItems);
loading = false;
}
});
Ces skills évoluent. Ajoute tes propres découvertes et patterns préférés.
development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
development
End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests. Use when Codex needs to run, rerun, debug, or interpret VM-based install, onboarding, gateway smoke tests, latest-release-to-main upgrade checks, fresh snapshot retests, or optional Discord roundtrip verification under Parallels.