feat(desktop): overlay réduit à une boule animée thinking-orbs (T-131) #124

Merged
ahitosly merged 4 commits from feat/T-131-overlay-orb-animations into main 2026-09-15 16:58:21 +02:00
Owner

Tâche

T-xxx — (titre dans docs/STATUS.md)

Changements

Contrat modifié ?

  • Non
  • Oui : packages/contract / supabase/migrations — docs/API.md / docs/DATA.md mis à jour, label contract, approbation humaine requise

Tests

  • scripts/check.sh vert
  • Test manuel (OS, scénario) :

Impacts cross-domaine

Fichiers hors périmètre de l'agent (et pourquoi) :

Suivi

  • docs/STATUS.md mis à jour (ligne de la tâche)
  • docs/CHANGELOG.md : entrée ajoutée sous Unreleased
  • docs/DECISIONS.md / docs/ECARTS.md mis à jour si décision ou écart
## Tâche T-xxx — (titre dans docs/STATUS.md) ## Changements - ## Contrat modifié ? - [ ] Non - [ ] Oui : `packages/contract` / `supabase/migrations` — `docs/API.md` / `docs/DATA.md` mis à jour, label `contract`, approbation humaine requise ## Tests - [ ] `scripts/check.sh` vert - [ ] Test manuel (OS, scénario) : ## Impacts cross-domaine Fichiers hors périmètre de l'agent (et pourquoi) : ## Suivi - [ ] `docs/STATUS.md` mis à jour (ligne de la tâche) - [ ] `docs/CHANGELOG.md` : entrée ajoutée sous Unreleased - [ ] `docs/DECISIONS.md` / `docs/ECARTS.md` mis à jour si décision ou écart
Remplace le VU-mètre à barres statique de l'overlay par thinking-orbs
(https://orbs.jakubantalik.com) : un orbe animé distinct selon l'état
(listening en écoute, solving en traitement, composing en réponse
agent), theme fixé en dark car la pilule est toujours sombre
indépendamment du thème OS, vitesse de l'orbe d'écoute légèrement
réactive au niveau de la voix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T7uSP86wxoW626f6apjpjN
Retire tout le chrome de l'overlay (pilule, texte, point de couleur,
raccourci Tab affiché) pour ne garder que l'orbe thinking-orbs,
demande directe de l'humain après le premier passage. Ajoute une
teinte par filtre SVG (feFlood+feComposite) : violet en mode agent
(cohérent avec --aria-agent déjà utilisé ailleurs), rouge en erreur.
Fenêtre overlay réduite à sa taille réelle (360x80 -> 96x96).

Corrige au passage un bug de transparence CSS latent : tokens.css
(chargé après le <style> inline de overlay.html dans le HTML compilé)
imposait background: var(--aria-bg) sur <body> à spécificité égale,
rendant la fenêtre overlay opaque malgré transparent:true -- invisible
tant que la pilule masquait l'artefact, critique dès qu'il ne reste
plus qu'une boule flottante.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T7uSP86wxoW626f6apjpjN
Bug réel trouvé par l'humain au 1er retour visuel : l'orbe listening
sautait en boucle pendant l'écoute, jamais pendant le traitement.
Cause identifiée par lecture du bundle thinking-orbs (index.es.js) :
sa phase d'animation est performance.now()/1000 * speed (temps absolu
depuis le montage, pas une intégration incrémentale), et speed est une
dépendance du useEffect qui recrée toute la boucle
requestAnimationFrame -- tout changement de speed recalcule la phase
avec un temps déjà énorme, provoquant un saut visuel instantané.
Le speed variable en fonction du rms (ajout précédent) déclenchait ça
plusieurs fois par seconde ; solving (traitement) n'a jamais ce
problème car son speed reste constant.

Retire la variation de speed : vitesse native de chaque preset,
jamais modifiée après montage.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T7uSP86wxoW626f6apjpjN
feat(desktop): allonger l'animation de fin de dictée à 300ms (T-131)
All checks were successful
ci / server (pull_request) Successful in 18s
ci / desktop-ts (pull_request) Successful in 29s
ci / desktop-rust (pull_request) Successful in 3m15s
c4dada5304
L'orbe "working" affiché pendant l'injection du texte disparaissait
dans la foulée du paste (quasi instantané, clipboard swap + raccourci
clavier) -- passait inaperçu. Réutilise l'infrastructure reset_after
existante (déjà utilisée pour Error/AgentMessage) : Injecting attend
désormais 300ms avant de revenir à Idle, sans écraser un état déjà
changé entre-temps (même garde que les deux autres cas).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T7uSP86wxoW626f6apjpjN
ahitosly scheduled this pull request to auto merge when all checks succeed 2026-09-15 16:58:06 +02:00
ahitosly deleted branch feat/T-131-overlay-orb-animations 2026-09-15 16:58:21 +02:00
Author
Owner

APPROVE (a posteriori — la PR est déjà mergée sur main au moment de cette review, cf. note ci-dessous).

Vérifié indépendamment (worktree isolé sur c75a3cf, sans faire confiance à l'affirmation de l'agent auteur) : scripts/check.sh vert — server 276 passed/1 skipped, desktop tsc/eslint clean, cargo clippy -D warnings/cargo test 155/155.

  1. Race should_reset_after_timeout/reset_after (session.rs:71-73,269,370-378) : pas de course trouvée. can_start (Idle uniquement) sérialise entièrement la machine à états — aucune nouvelle session ne peut démarrer tant qu'Injecting n'est pas retombé à Idle, donc jamais deux minuteurs reset_after concurrents sur le même "bucket". Point non-bloquant à noter : ça introduit une vraie fenêtre de ~300ms (contre ~10ms avant, durée du paste() sync) pendant laquelle un appui hotkey juste après une dictée est silencieusement ignoré (start() retourne tôt, aucun retour visuel) — comportement différent, jamais testé physiquement (cf. STATUS.md "Vérifications manuelles en attente" T-131, pas d'accès GUI). Pas un bug de logique, juste un compromis latence-résiduelle/pas de feedback à surveiller si un usage de dictées rapprochées se manifeste.

  2. Autres call sites de Injecting/Idle : seulement tray.rs::icon_bytes_for (groupe Injecting avec les autres icônes "actif", cohérent) et Overlay.tsx::orbFor (mapping visuel). Aucune régression trouvée par grep exhaustif.

  3. !important overlay.html:16 : bien scopé à cette seule page. Vérifié que index.html/agent.html sont des entrées Vite séparées avec leurs propres <style> inline (agent.html n'a pas de règle background, index.html aucune) — tokens.css::body{background:var(--aria-bg)} (non !important) continue de s'appliquer normalement à settings/agent, pas de fuite.

  4. Filtre SVG feFlood+feComposite operator="in" : solide. Confirmé par lecture du bundle réel (thinking-orbs@0.3.1/dist/index.es.js) que ThinkingOrb rend un <canvas> et que style.filter (dont url(#orb-tint-*)) s'applique dessus comme n'importe quel filtre CSS — dégradation gracieuse si non supporté (l'orbe resterait visible en encre native, pas de crash/disparition). Coût perf négligeable (canvas 64px, filtre composité GPU, pas de travail JS supplémentaire par frame). Le retrait de speed dérivé du rms est confirmé exact par lecture du même bundle : useEffect deps [t, e, y, r, i, E], phase performance.now()/1000*speed — diagnostic du rebond vérifié indépendamment, correct.

  5. Tests Rust cohérents avec le nouveau comportement (should_reset_after_timeout_only_from_error_agent_message_or_injecting couvre bien les 3 cas + les négatifs).

  6. Cross-domaine (windows.rs/tauri.conf.json par une tâche ui-ux) correctement signalé dans la PR et STATUS.md. Pas de contrat/migration/secret touché.

Note hors scope de cette PR, trouvée pendant la review : session.rs (ligne inchangée par ce diff) logge le texte dicté en clair au niveau info (log::info!("dictée traitée et injectée (...) : {text:?}")) — décision documentée et assumée en T-041/PR#50 pour satisfaire littéralement le critère M2, mais en tension avec l'exigence "texte dicté jamais loggué en INFO". Pré-existant, non introduit par #124, à traiter séparément si pertinent (M2 est clos depuis longtemps, la justification d'origine ne tient peut-être plus).

Constat opérationnel important pour la suite : au moment de cette review, la PR est déjà state=closed merged=True sur origin/main (commit squash c75a3cf) — le merge automatique programmé s'est déclenché avant/pendant cette review, la CI étant déjà verte. Aucun problème bloquant trouvé, donc pas d'impact ici, mais si un problème avait été trouvé il aurait fallu un correctif de suivi plutôt qu'un blocage du merge.

APPROVE (a posteriori — la PR est déjà mergée sur main au moment de cette review, cf. note ci-dessous). Vérifié indépendamment (worktree isolé sur c75a3cf, sans faire confiance à l'affirmation de l'agent auteur) : `scripts/check.sh` vert — server 276 passed/1 skipped, desktop `tsc`/`eslint` clean, `cargo clippy -D warnings`/`cargo test` 155/155. 1. Race `should_reset_after_timeout`/`reset_after` (session.rs:71-73,269,370-378) : pas de course trouvée. `can_start` (Idle uniquement) sérialise entièrement la machine à états — aucune nouvelle session ne peut démarrer tant qu'`Injecting` n'est pas retombé à `Idle`, donc jamais deux minuteurs `reset_after` concurrents sur le même "bucket". Point non-bloquant à noter : ça introduit une vraie fenêtre de ~300ms (contre ~10ms avant, durée du `paste()` sync) pendant laquelle un appui hotkey juste après une dictée est silencieusement ignoré (`start()` retourne tôt, aucun retour visuel) — comportement différent, jamais testé physiquement (cf. STATUS.md "Vérifications manuelles en attente" T-131, pas d'accès GUI). Pas un bug de logique, juste un compromis latence-résiduelle/pas de feedback à surveiller si un usage de dictées rapprochées se manifeste. 2. Autres call sites de `Injecting`/`Idle` : seulement `tray.rs::icon_bytes_for` (groupe `Injecting` avec les autres icônes "actif", cohérent) et `Overlay.tsx::orbFor` (mapping visuel). Aucune régression trouvée par grep exhaustif. 3. `!important` overlay.html:16 : bien scopé à cette seule page. Vérifié que `index.html`/`agent.html` sont des entrées Vite séparées avec leurs propres `<style>` inline (agent.html n'a pas de règle `background`, index.html aucune) — `tokens.css::body{background:var(--aria-bg)}` (non `!important`) continue de s'appliquer normalement à `settings`/`agent`, pas de fuite. 4. Filtre SVG `feFlood`+`feComposite operator="in"` : solide. Confirmé par lecture du bundle réel (`thinking-orbs@0.3.1/dist/index.es.js`) que `ThinkingOrb` rend un `<canvas>` et que `style.filter` (dont `url(#orb-tint-*)`) s'applique dessus comme n'importe quel filtre CSS — dégradation gracieuse si non supporté (l'orbe resterait visible en encre native, pas de crash/disparition). Coût perf négligeable (canvas 64px, filtre composité GPU, pas de travail JS supplémentaire par frame). Le retrait de `speed` dérivé du `rms` est confirmé exact par lecture du même bundle : `useEffect` deps `[t, e, y, r, i, E]`, phase `performance.now()/1000*speed` — diagnostic du rebond vérifié indépendamment, correct. 5. Tests Rust cohérents avec le nouveau comportement (`should_reset_after_timeout_only_from_error_agent_message_or_injecting` couvre bien les 3 cas + les négatifs). 6. Cross-domaine (`windows.rs`/`tauri.conf.json` par une tâche ui-ux) correctement signalé dans la PR et STATUS.md. Pas de contrat/migration/secret touché. Note hors scope de cette PR, trouvée pendant la review : `session.rs` (ligne inchangée par ce diff) logge le texte dicté en clair au niveau `info` (`log::info!("dictée traitée et injectée (...) : {text:?}")`) — décision documentée et assumée en T-041/PR#50 pour satisfaire littéralement le critère M2, mais en tension avec l'exigence "texte dicté jamais loggué en INFO". Pré-existant, non introduit par #124, à traiter séparément si pertinent (M2 est clos depuis longtemps, la justification d'origine ne tient peut-être plus). Constat opérationnel important pour la suite : au moment de cette review, la PR est déjà state=closed merged=True sur origin/main (commit squash c75a3cf) — le merge automatique programmé s'est déclenché avant/pendant cette review, la CI étant déjà verte. Aucun problème bloquant trouvé, donc pas d'impact ici, mais si un problème avait été trouvé il aurait fallu un correctif de suivi plutôt qu'un blocage du merge.
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
cloud-rennais/aria!124
No description provided.