Skip to content

Commit 2a472ed

Browse files
authored
Merge pull request #253 from sora520/fix/windows-capsule-visuals
fix(windows): stabilize capsule visuals and audio meter
2 parents 003b713 + 23d7f44 commit 2a472ed

3 files changed

Lines changed: 21 additions & 15 deletions

File tree

openless-all/app/src/components/Capsule.tsx

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,14 @@ interface AudioBarsProps {
1515

1616
function AudioBars({ level }: AudioBarsProps) {
1717
const envelope = [0.55, 0.85, 1.0, 0.85, 0.55];
18-
const base = 4;
19-
const max = 18;
18+
const base = 2;
19+
const max = 24;
2020
const voice = Math.min(1, Math.max(0, level));
21+
const silenceGate = 0.012;
22+
const responseCeiling = 0.34;
23+
const gatedVoice = Math.min(1, Math.max(0, (voice - silenceGate) / (responseCeiling - silenceGate)));
24+
const easedVoice = gatedVoice * gatedVoice * (3 - 2 * gatedVoice);
25+
const visualVoice = Math.pow(easedVoice, 0.42);
2126
return (
2227
<div
2328
style={{
@@ -35,10 +40,11 @@ function AudioBars({ level }: AudioBarsProps) {
3540
style={{
3641
display: 'inline-block',
3742
width: 3,
38-
height: base + (max - base) * voice * env,
43+
height: base + (max - base) * visualVoice * env,
3944
borderRadius: 999,
4045
background: 'var(--ol-blue)',
4146
opacity: 0.82,
47+
transformOrigin: 'center',
4248
transition: 'height 0.08s var(--ol-motion-quick)',
4349
}}
4450
/>
@@ -108,6 +114,8 @@ interface CircleButtonProps {
108114
function CircleButton({ variant, enabled, onClick }: CircleButtonProps) {
109115
const { t } = useTranslation();
110116
const isCancel = variant === 'cancel';
117+
const os = detectOS();
118+
const useBackdrop = os !== 'win' && isCancel;
111119
return (
112120
<button
113121
onClick={enabled ? onClick : undefined}
@@ -118,15 +126,16 @@ function CircleButton({ variant, enabled, onClick }: CircleButtonProps) {
118126
height: 28,
119127
borderRadius: 999,
120128
background: isCancel ? 'rgba(255, 255, 255, 0.55)' : 'rgba(255, 255, 255, 0.92)',
121-
backdropFilter: isCancel ? 'blur(12px) saturate(160%)' : 'none',
122-
WebkitBackdropFilter: isCancel ? 'blur(12px) saturate(160%)' : 'none',
129+
backdropFilter: useBackdrop ? 'blur(12px) saturate(160%)' : 'none',
130+
WebkitBackdropFilter: useBackdrop ? 'blur(12px) saturate(160%)' : 'none',
123131
color: 'var(--ol-ink)',
124132
border: '0.8px solid rgba(0, 0, 0, 0.08)',
125133
display: 'inline-flex',
126134
alignItems: 'center',
127135
justifyContent: 'center',
128136
cursor: enabled ? 'default' : 'not-allowed',
129137
opacity: enabled ? 1 : 0.42,
138+
visibility: 'visible',
130139
flexShrink: 0,
131140
padding: 0,
132141
boxShadow: '0 1px 2px rgba(0, 0, 0, 0.06)',
@@ -217,9 +226,7 @@ function Pill({ os, state, level, insertedChars, message, onCancel, onConfirm }:
217226
const ambient = state === 'recording' ? Math.min(1, Math.max(0, level)) : 0;
218227
const scale = os === 'win' ? 1 : 1 + ambient * 0.018;
219228
const shadowAlpha = 0.20 + ambient * 0.10;
220-
const dropShadow = os === 'win'
221-
? `drop-shadow(0 12px 24px rgba(0, 0, 0, ${(0.15 + ambient * 0.06).toFixed(3)}))`
222-
: 'none';
229+
const useBackdrop = os !== 'win';
223230

224231
return (
225232
<div
@@ -233,23 +240,22 @@ function Pill({ os, state, level, insertedChars, message, onCancel, onConfirm }:
233240
height: metrics.height,
234241
borderRadius: 999,
235242
background: 'rgba(255, 255, 255, 0.62)',
236-
backdropFilter: 'blur(28px) saturate(180%)',
237-
WebkitBackdropFilter: 'blur(28px) saturate(180%)',
243+
backdropFilter: useBackdrop ? 'blur(28px) saturate(180%)' : 'none',
244+
WebkitBackdropFilter: useBackdrop ? 'blur(28px) saturate(180%)' : 'none',
238245
border: '1px solid rgba(255, 255, 255, 0.55)',
239246
boxShadow: os === 'win'
240-
? '0 0 0 0.5px rgba(0, 0, 0, 0.08), inset 0 0.5px 0 rgba(255, 255, 255, 0.55)'
247+
? `0 10px 24px -14px rgba(0, 0, 0, ${(0.24 + ambient * 0.06).toFixed(3)}), 0 0 0 0.5px rgba(0, 0, 0, 0.08), inset 0 0.5px 0 rgba(255, 255, 255, 0.55)`
241248
: `0 18px 50px -10px rgba(0, 0, 0, ${shadowAlpha.toFixed(3)}), 0 0 0 0.5px rgba(0, 0, 0, 0.08), inset 0 0.5px 0 rgba(255, 255, 255, 0.55)`,
242249
color: 'var(--ol-ink)',
243250
fontFamily: 'var(--ol-font-sans)',
244251
transform: `scale(${scale.toFixed(4)})`,
245252
transformOrigin: 'center',
246253
transition: 'transform 0.08s var(--ol-motion-quick), box-shadow 0.08s var(--ol-motion-quick)',
247254
willChange: 'transform, box-shadow',
248-
filter: dropShadow,
249255
}}
250256
>
251257
<CircleButton variant="cancel" enabled={enabled} onClick={onCancel} />
252-
<div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
258+
<div style={{ flex: 1, minWidth: 0, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
253259
{center}
254260
</div>
255261
<CircleButton variant="confirm" enabled={enabled} onClick={onConfirm} />

openless-all/app/src/lib/capsuleLayout.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function assertEqual<T>(actual: T, expected: T, name: string) {
1212
const winMetrics = getCapsulePillMetrics('win');
1313
assertEqual(winMetrics.width, 196, 'windows capsule widens pill');
1414
assertEqual(winMetrics.height, 52, 'windows capsule increases pill height');
15-
assertEqual(winMetrics.textWidth, 118, 'windows capsule widens text slot');
15+
assertEqual(winMetrics.textWidth, 104, 'windows capsule keeps side controls clear');
1616

1717
const macMetrics = getCapsulePillMetrics('mac');
1818
assertEqual(macMetrics.width, 176, 'mac capsule keeps existing pill width');

openless-all/app/src/lib/capsuleLayout.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export interface CapsuleMessageLayout {
2222

2323
export function getCapsulePillMetrics(os: OS): CapsulePillMetrics {
2424
if (os === 'win') {
25-
return { width: 196, height: 52, textWidth: 118 };
25+
return { width: 196, height: 52, textWidth: 104 };
2626
}
2727

2828
return { width: 176, height: 42, textWidth: 84 };

0 commit comments

Comments
 (0)