Created
August 31, 2025 07:23
-
-
Save ragingwind/dc6242ed004a103da64822397dfcea6c to your computer and use it in GitHub Desktop.
loading indicator with half-tone dot wave animation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use client'; | |
import { useEffect, useRef } from 'react'; | |
export function StreamingIndicator() { | |
const canvasRef = useRef<HTMLCanvasElement>(null); | |
useEffect(() => { | |
const canvas = canvasRef.current; | |
if (!canvas) return; | |
const ctx = canvas.getContext('2d'); | |
if (!ctx) return; | |
// Set canvas size to match the 24x24px indicator | |
canvas.width = 24; | |
canvas.height = 24; | |
let animationId: number; | |
let time = 0; | |
const animate = () => { | |
ctx.fillStyle = '#ff9729'; | |
ctx.fillRect(0, 0, canvas.width, canvas.height); | |
const centerX = canvas.width / 2; | |
const centerY = canvas.height / 2; | |
const maxRadius = Math.min(canvas.width, canvas.height) / 2; | |
// Create cleaner halftone pattern with reduced pixels | |
for (let x = 2; x < canvas.width; x += 4) { | |
for (let y = 2; y < canvas.height; y += 4) { | |
const distance = Math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2); | |
const normalizedDistance = distance / maxRadius; | |
// Simple breathing pattern | |
const breathe = Math.sin(time * 0.08) * 0.3 + 0.7; | |
const falloff = Math.max(0, 1 - normalizedDistance); | |
const size = breathe * falloff * 1.2; | |
if (size > 0.2) { | |
ctx.fillStyle = '#ffffff'; | |
ctx.beginPath(); | |
ctx.arc(x, y, size, 0, Math.PI * 2); | |
ctx.fill(); | |
} | |
} | |
} | |
time += 1; | |
animationId = requestAnimationFrame(animate); | |
}; | |
animate(); | |
return () => { | |
if (animationId) { | |
cancelAnimationFrame(animationId); | |
} | |
}; | |
}, []); | |
return ( | |
<div className="flex items-start space-x-3 mb-6"> | |
<div className="flex-shrink-0"> | |
<div className="w-6 h-6 bg-[#ff9729] rounded-full flex items-center justify-center relative shadow-inner overflow-hidden"> | |
<canvas | |
ref={canvasRef} | |
className="w-full h-full" | |
style={{ imageRendering: 'pixelated' }} | |
/> | |
</div> | |
</div> | |
</div> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment