renderReticle method
Renders the reticle (crosshair) at screen center with dwell feedback: an accent progress ring, tick marks, and a selection flash.
Implementation
void renderReticle(Canvas canvas, Size viewportSize) {
final center = Offset(viewportSize.width / 2, viewportSize.height / 2);
const baseRadius = 4.0;
final dwellRadius = baseRadius + dwellProgress * 8;
final hasTarget = _gazeTargetId != null;
// Outer ring (dwell progress) with color ramp white -> accent.
if (dwellProgress > 0) {
final ringColor = Color.lerp(
const Color(0xFFFFFFFF),
const Color(0xFF2E90FA),
dwellProgress,
)!;
canvas.drawArc(
Rect.fromCircle(center: center, radius: dwellRadius),
-1.5708, // Start at top
dwellProgress * 6.2832, // Full circle
false,
Paint()
..color = ringColor
..style = PaintingStyle.stroke
..strokeWidth = 2,
);
// Tick marks at quarter positions for readable progress.
final tickPaint = Paint()
..color = ringColor.withValues(alpha: 0.7)
..strokeWidth = 1.5;
for (var i = 0; i < 4; i++) {
final angle = -1.5708 + i * 1.5708;
final inner = Offset(
center.dx + (dwellRadius - 3) * math.cos(angle),
center.dy + (dwellRadius - 3) * math.sin(angle),
);
final outer = Offset(
center.dx + (dwellRadius + 3) * math.cos(angle),
center.dy + (dwellRadius + 3) * math.sin(angle),
);
canvas.drawLine(inner, outer, tickPaint);
}
}
// Selection flash: expanding ring fading out right after dwell-select.
if (_selected) {
canvas.drawCircle(
center,
dwellRadius + 4,
Paint()
..color = const Color(0x662E90FA)
..style = PaintingStyle.stroke
..strokeWidth = 3,
);
}
// Hover halo when a target is gazed but dwell has not started.
if (hasTarget && dwellProgress == 0) {
canvas.drawCircle(
center,
baseRadius + 4,
Paint()
..color = const Color(0x40FFFFFF)
..style = PaintingStyle.stroke
..strokeWidth = 1,
);
}
// Center dot
canvas.drawCircle(
center,
hasTarget ? 3 : 2,
Paint()..color = const Color(0xCCFFFFFF),
);
}