Typing Sound Input
Champ de saisie avec retour sonore à chaque frappe : oscillateur square 300–500 Hz via Web Audio API, barre de progression CSS — zéro dépendance, zéro canvas.
Vous aurez accès à la démo interactive avec un compte gratuit.
Cet effet fait partie d'Effect.Labs — 811 effets vanilla, une partie gratuite, une partie premium. Atmosphère comprend 57 effets, dont 10 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
À chaque événement keydown, un OscillatorNode de type square est instancié via l'API Web Audio. La fréquence est tirée aléatoirement entre 300 et 500 Hz (300 + Math.random() * 200) pour varier légèrement le timbre entre deux touches consécutives et imiter la variabilité d'un vrai clavier. La durée totale du son est de 50 ms.
Le volume suit un profil d'enveloppe exponentielle : le GainNode démarre à 0,02, puis exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.05) ramène le gain à presque zéro en 50 ms. Ce profil — attaque instantanée, déclin rapide — produit le click percussif caractéristique d'une touche mécanique sans résonance longue. L'oscillateur est arrêté et libéré automatiquement à t+50 ms (stop()), aucune fuite mémoire.
L'AudioContext est créé en singleton lazy (getSndCtx()) avec fallback webkitAudioContext pour Safari ≤ 14. Il reste suspendu jusqu'au premier keydown — conforme à la politique de geste utilisateur requis imposée par Chrome 71+ et Safari 12.1+.
La barre de progression (.snd-typing-bar) est une <div> dont la largeur est recalculée en CSS pur à chaque frappe : Math.min(100, (input.value.length + 1) × 5) + '%'. Elle atteint 100 % à 20 caractères. La propriété CSS transition: width .1s lisse l'animation sans RAF ni JS supplémentaire.
Accessibilité
- prefers-reduced-motion : absent du code. La barre CSS (
transition: width .1s) n'est pas supprimée si l'OS active « Réduire les animations » — prévoir une règle@media (prefers-reduced-motion: reduce) { .snd-typing-bar { transition: none } }pour être conforme WCAG 2.3.3. - Le son n'est pas déclenché automatiquement : l'AudioContext ne démarre qu'après la première frappe clavier. Aucun bruit intempestif au chargement de page — conforme au critère WCAG 1.4.2 (contrôle audio).
- L'
<input>est nativement focusable au clavier et navigable au Tab. En revanche, il n'est associé à aucun<label>dans le code fourni — seul leplaceholdersert d'étiquette, ce qui est une lacune pour les lecteurs d'écran (WCAG 1.3.1). Ajouter un<label for="sndTypingInput">ou unaria-labelen intégration. - La barre
.snd-typing-indicatorne porte nirole="progressbar"niaria-valuenow/aria-valuemax— la progression n'est pas restituée par les lecteurs d'écran. Compléter si la métrique a une valeur sémantique pour l'utilisateur. - Contraste texte : l'input sur fond
#0a0a0f+ couleur#fffatteint un ratio ≥ 15:1 (WCAG AA et AAA). Le placeholder à 70 % d'opacité blanc descend vers ~10:1 — toujours conforme AA.
Compatibilité navigateur
Nécessite Web Audio API — disponible dans tous les navigateurs modernes depuis 2014. Zéro dépendance externe, zéro canvas.
Si <code>AudioContext</code> et <code>webkitAudioContext</code> sont tous deux absents (IE 11, Opera Mini), la fonction <code>playTone</code> lève une erreur silencieuse (le bloc de création oscillo n'est jamais atteint). Le champ de saisie et la barre de progression restent entièrement fonctionnels — seul le son est absent.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="snd-typing-container">
<input
type="text"
class="snd-typing-input"
id="sndTypingInput"
placeholder="Tapez quelque chose..."
>
<div class="snd-typing-indicator">
<div class="snd-typing-bar" id="sndTypingBar"></div>
</div>
</div>
HTML + CSS + JS complet, prêt à coller — avec des centaines d'effets premium.
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
| Plage de fréquence | 300–500 Hz | Dans le listener keydown du JS, modifier 300 + Math.random() * 200. Exemple : 200 + Math.random() * 100 donne un son plus grave (typewriter vintage) ; 500 + Math.random() * 300 donne un son plus aigu (clavier chiclet). |
| Type d'onde oscillateur | 'square' | 3e argument de playTone(freq, 0.05, 'square', 0.02). 'sine' = doux et rond, 'triangle' = neutre, 'sawtooth' = plus électronique et brillant. 'square' produit le timbre le plus proche d'un relais mécanique. |
| Durée du son | 0.05 s (50 ms) | 2e argument de playTone. 0.05 = click sec de touche, 0.12 = note piano légère, 0.20 = timbre d'orgue perceptible. Réduire sous 0.03 pour un son presque imperceptible. |
| Volume (gain initial) | 0.02 | 4e argument de playTone. 0.02 = discret (fond sonore), 0.05 = présent, 0.10 = fort. Rester sous 0.08 pour ne pas surprendre un utilisateur avec des écouteurs. |
| Couleur de la barre | #6366f1 | Propriété CSS background de .snd-typing-bar. Remplacez par le primary de votre charte. Supporte les dégradés : linear-gradient(90deg, #6366f1, #ec4899). |
| Taux de remplissage de la barre | × 5 (100 % à 20 chars) | Dans le calcul Math.min(100, (input.value.length + 1) * 5), modifier le multiplicateur : * 3 → 100 % à 33 chars (e-mail long), * 10 → 100 % à 10 chars (code PIN). |
| Vitesse de la transition CSS | 0.1 s | Propriété transition: width .1s de .snd-typing-bar. Passer à .3s ease-out pour un effet de remplissage plus fluide, ou none pour un affichage instantané (et conforme à prefers-reduced-motion). |
FAQ
AudioContext jusqu'à un geste utilisateur explicite (clic ou frappe). Le premier keydown crée et résume le contexte — le son est absent sur cette seule frappe. C'est un comportement navigateur, non un bug. Pour contourner, appeler getSndCtx().resume() dans un handler de clic sur la page (bouton « Activer le son ») avant que l'utilisateur ne commence à taper.document.getElementById('sndTypingInput') au moment de son exécution — le DOM doit être monté. Dans React, enveloppez l'initialisation dans un useEffect(() => { /* exécuter le script */ }, []) ou utilisez une ref directement. Dans Vue, appelez-le dans le hook mounted(). Pour des instances multiples, générez des IDs uniques par composant (ex. sndTypingInput-${uuid}) et instanciez le listener manuellement.AudioBufferSourceNode chargé avec AudioContext.decodeAudioData(). Chargez le WAV/MP3 une fois au montage, stockez l'AudioBuffer, et à chaque frappe créez un nouveau AudioBufferSourceNode, connectez-le au GainNode, et appelez start(). La structure du listener reste identique — seule la source audio change.