hermes(voice): keep one consistent ellipsis on conversation status labels
The overlay status caption already carries a static ellipsis (e.g. 'Thinking…'), and after ~2.5s of silent thinking the 'working' affordance added an animated dots ::after on top of it — so the label intermittently rendered as 'Thinking……' only on longer turns. Drop the animated text dots and keep the orb-halo shimmer as the liveness cue, so the ellipsis stays a single, consistent static one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BvMSXH8VH2tMWXanb8SJdf
This commit is contained in:
parent
9f49a1ba2c
commit
5b1f832072
@ -809,38 +809,21 @@
|
||||
filter: saturate(0.35) brightness(0.8);
|
||||
}
|
||||
|
||||
/* FIX 4: "working…" affordance. Armed by atlas-voice.js (.is-awaiting) only
|
||||
/* FIX 4: "working" affordance. Armed by atlas-voice.js (.is-awaiting) only
|
||||
after the model has been Thinking a beat with no reply text yet, so dead time
|
||||
reads as alive. A slow orb shimmer plus animated dots trailing the state
|
||||
caption — cheap, CSS-only, and fully suppressed under reduced motion by the
|
||||
blanket rule below. */
|
||||
reads as alive. A slow orb shimmer only — the state caption keeps its single
|
||||
static ellipsis (e.g. "Thinking…") and is never trailed by animated dots, so
|
||||
the ellipsis stays consistent instead of doubling up. Cheap, CSS-only, and
|
||||
fully suppressed under reduced motion by the blanket rule below. */
|
||||
.voice-conversation.is-awaiting .voice-conversation-orb-halo {
|
||||
animation: voice-conversation-await-shimmer 2.6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.voice-conversation.is-awaiting .voice-conversation-state::after {
|
||||
content: "";
|
||||
display: inline-block;
|
||||
width: 1.4em;
|
||||
margin-left: 0.15em;
|
||||
text-align: left;
|
||||
vertical-align: bottom;
|
||||
animation: voice-conversation-await-dots 1.4s steps(4, end) infinite;
|
||||
}
|
||||
|
||||
@keyframes voice-conversation-await-shimmer {
|
||||
0%, 100% { opacity: 0.6; filter: blur(10px); }
|
||||
50% { opacity: 0.92; filter: blur(13px); }
|
||||
}
|
||||
|
||||
@keyframes voice-conversation-await-dots {
|
||||
0% { content: ""; }
|
||||
25% { content: "·"; }
|
||||
50% { content: "··"; }
|
||||
75% { content: "···"; }
|
||||
100% { content: ""; }
|
||||
}
|
||||
|
||||
@keyframes voice-conversation-breathe {
|
||||
0%, 100% { opacity: 0.55; transform: scale(calc(0.96 + (var(--conversation-level) * 0.3))); }
|
||||
50% { opacity: 0.85; transform: scale(calc(1.05 + (var(--conversation-level) * 0.3))); }
|
||||
|
||||
@ -629,6 +629,13 @@ def test_conversation_thinking_working_affordance_contract():
|
||||
# The affordance disarms the instant any reply text arrives.
|
||||
assert "if(text&&String(text).trim()) clearAwaitingAffordance();" in source
|
||||
assert ".voice-conversation.is-awaiting" in css
|
||||
# The affordance is an orb shimmer only: the state caption keeps its single
|
||||
# static ellipsis and is never trailed by animated dots, so "Thinking…" can
|
||||
# never render as "Thinking……". (Consistency fix.)
|
||||
assert "voice-conversation-await-shimmer" in css
|
||||
assert "voice-conversation-await-dots" not in css
|
||||
assert ".voice-conversation-state::after" not in css
|
||||
assert "thinking:'Thinking…'" in source and "transcribing:'Transcribing…'" in source
|
||||
# Reduced motion suppresses every overlay animation, including this one.
|
||||
rm_block = css.split("@media (prefers-reduced-motion: reduce)", 1)[1]
|
||||
assert "animation: none !important" in rm_block
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user