Skip to content

Commit d29f024

Browse files
ofriwclaude
andcommitted
Make U-shaped attention curve animation more descriptive
- Curve width now represents context length (not just depth for attention) - Added dual baselines: static (full width) and dynamic (active context span) - Non-linear width scaling for visual clarity at different context levels - Improved control point calculations for smooth curves at all widths - Updated labels to show percentages and clarify what curve dimensions represent - Enhanced explanation text to describe both width (length) and depth (attention quality) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 0bdaa5f commit d29f024

File tree

1 file changed

+62
-22
lines changed

1 file changed

+62
-22
lines changed

website/src/components/VisualElements/UShapeAttentionCurve.tsx

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export default function UShapeAttentionCurve({
1010
}: UShapeAttentionCurveProps) {
1111
const [contextFill, setContextFill] = useState(initialContextFill);
1212
const [animatedPath, setAnimatedPath] = useState<string>('');
13+
const [animatedEndX, setAnimatedEndX] = useState<number>(0);
14+
const [animatedMiddleX, setAnimatedMiddleX] = useState<number>(0);
1315
const previousPathRef = useRef<string>('');
1416
const animationFrameRef = useRef<number | null>(null);
1517

@@ -19,23 +21,39 @@ export default function UShapeAttentionCurve({
1921
const padding = 70;
2022

2123
// Calculate curve parameters based on context fill percentage
22-
// More context = deeper U (worse middle attention)
24+
// More context = deeper U (worse middle attention) AND wider span (longer context)
2325
const curveDepth = 50 + (contextFill / 100) * 100; // Range: 50-150
2426

27+
// Calculate available width for curve
28+
const availableWidth = width - 2 * padding;
29+
30+
// Non-linear mapping for visual clarity: 90% context uses full available width
31+
const getVisualWidth = (contextPercent: number): number => {
32+
if (contextPercent <= 30) return 0.3;
33+
if (contextPercent <= 60) return 0.3 + (contextPercent - 30) * (0.3 / 30);
34+
return 0.6 + (contextPercent - 60) * (0.4 / 30);
35+
};
36+
37+
const scaledWidth = availableWidth * getVisualWidth(contextFill);
38+
2539
// Define the U-shaped curve using cubic Bézier
2640
// Start high (left), dip low (middle), end high (right)
2741
const startX = padding;
2842
const startY = padding;
29-
const endX = width - padding;
43+
const endX = startX + scaledWidth;
3044
const endY = padding;
31-
const middleX = width / 2;
45+
const middleX = (startX + endX) / 2; // Middle of the actual curve span
3246
const middleY = padding + curveDepth;
3347

3448
// Cubic Bézier path: smooth curve through three points
49+
// Use proportional control points for smooth curves at all widths
50+
const controlOffset = scaledWidth / 6; // 1/3 of half-width for smooth shoulders
51+
const verticalSmoothing = (middleY - startY) * 0.3; // 30% interpolation for gentle transitions
52+
3553
const curvePath = `
3654
M ${startX},${startY}
37-
C ${startX + 100},${startY} ${middleX - 100},${middleY} ${middleX},${middleY}
38-
C ${middleX + 100},${middleY} ${endX - 100},${startY} ${endX},${endY}
55+
C ${startX + controlOffset},${startY + verticalSmoothing} ${middleX - controlOffset},${middleY} ${middleX},${middleY}
56+
C ${middleX + controlOffset},${middleY} ${endX - controlOffset},${startY + verticalSmoothing} ${endX},${endY}
3957
`.trim();
4058

4159
// Animate path morphing for Safari compatibility
@@ -44,6 +62,8 @@ export default function UShapeAttentionCurve({
4462
if (!previousPathRef.current) {
4563
previousPathRef.current = curvePath;
4664
setAnimatedPath(curvePath);
65+
setAnimatedEndX(endX);
66+
setAnimatedMiddleX(middleX);
4767
return;
4868
}
4969

@@ -115,11 +135,15 @@ export default function UShapeAttentionCurve({
115135
const interpolatedPath = `M ${m1},${m2} C ${c1},${c2} ${c3},${c4} ${c5},${c6} C ${c7},${c8} ${c9},${c10} ${c11},${c12}`;
116136

117137
setAnimatedPath(interpolatedPath);
138+
setAnimatedEndX(c11); // Track the animated endpoint X coordinate
139+
setAnimatedMiddleX(c5); // Track the animated middle point X coordinate
118140

119141
if (progress < 1) {
120142
animationFrameRef.current = requestAnimationFrame(animate);
121143
} else {
122144
previousPathRef.current = curvePath;
145+
setAnimatedEndX(endX); // Ensure final position is exact
146+
setAnimatedMiddleX(middleX); // Ensure final position is exact
123147
}
124148
};
125149

@@ -135,9 +159,12 @@ export default function UShapeAttentionCurve({
135159
}, [curvePath]);
136160

137161
// Area fill path (curve + bottom edge for filled area)
162+
// Use animatedEndX to keep the right edge synchronized during transitions
163+
const currentEndX = animatedEndX || endX;
164+
const currentMiddleX = animatedMiddleX || middleX;
138165
const areaPath = `
139166
${animatedPath || curvePath}
140-
L ${endX},${height - padding}
167+
L ${currentEndX},${height - padding}
141168
L ${startX},${height - padding}
142169
Z
143170
`.trim();
@@ -146,9 +173,9 @@ export default function UShapeAttentionCurve({
146173
const gradientId = 'attentionGradient';
147174

148175
const contextLevels = [
149-
{ label: 'Light', value: 30 },
150-
{ label: 'Medium', value: 60 },
151-
{ label: 'Heavy', value: 90 },
176+
{ label: 'Light (30%)', value: 30 },
177+
{ label: 'Medium (60%)', value: 60 },
178+
{ label: 'Heavy (90%)', value: 90 },
152179
];
153180

154181
return (
@@ -204,13 +231,25 @@ export default function UShapeAttentionCurve({
204231
</defs>
205232

206233
{/* Background grid for reference */}
234+
{/* Static baseline showing full available width */}
207235
<line
208-
x1={startX}
236+
x1={padding}
209237
y1={height - padding}
210-
x2={endX}
238+
x2={width - padding}
211239
y2={height - padding}
212-
stroke="var(--ifm-color-emphasis-300)"
240+
stroke="var(--ifm-color-emphasis-200)"
213241
strokeWidth="1"
242+
opacity="0.5"
243+
/>
244+
245+
{/* Dynamic baseline showing active context span */}
246+
<line
247+
x1={startX}
248+
y1={height - padding}
249+
x2={currentEndX}
250+
y2={height - padding}
251+
stroke="var(--ifm-color-emphasis-400)"
252+
strokeWidth="2"
214253
strokeDasharray="4 4"
215254
/>
216255

@@ -278,15 +317,15 @@ export default function UShapeAttentionCurve({
278317
</text>
279318

280319
<text
281-
x={middleX}
320+
x={currentMiddleX}
282321
y={height - padding + 30}
283322
textAnchor="middle"
284323
className={styles.label}
285324
>
286325
Middle
287326
</text>
288327
<text
289-
x={middleX}
328+
x={currentMiddleX}
290329
y={height - padding + 50}
291330
textAnchor="middle"
292331
className={styles.sublabel}
@@ -295,15 +334,15 @@ export default function UShapeAttentionCurve({
295334
</text>
296335

297336
<text
298-
x={endX}
337+
x={currentEndX}
299338
y={height - padding + 30}
300339
textAnchor="middle"
301340
className={styles.label}
302341
>
303342
End
304343
</text>
305344
<text
306-
x={endX}
345+
x={currentEndX}
307346
y={height - padding + 50}
308347
textAnchor="middle"
309348
className={styles.sublabel}
@@ -348,7 +387,7 @@ export default function UShapeAttentionCurve({
348387
</svg>
349388

350389
<div className={styles.controls}>
351-
<span className={styles.controlLabel}>Context Usage:</span>
390+
<span className={styles.controlLabel}>Context Length:</span>
352391
{contextLevels.map((level) => (
353392
<button
354393
key={level.value}
@@ -363,11 +402,12 @@ export default function UShapeAttentionCurve({
363402
</div>
364403

365404
<div className={styles.explanation}>
366-
<strong>The U-Curve Effect:</strong> As context usage increases, the
367-
attention drop in the middle becomes more pronounced. With light usage,
368-
degradation is minimal. With medium usage, the U-curve becomes
369-
noticeable. With heavy usage, only the beginning and end are reliably
370-
processed.
405+
<strong>The U-Curve Effect:</strong> The curve's width shows context
406+
length, while depth shows attention quality. As context length increases,
407+
the attention drop in the middle becomes more pronounced. Short contexts
408+
(30%) have minimal degradation. Medium contexts (60%) show a noticeable
409+
U-curve. Long contexts (90%) exhibit severe attention loss—only the
410+
beginning and end are reliably processed.
371411
</div>
372412
</div>
373413
);

0 commit comments

Comments
 (0)