fix: DrillOrbit fades in/out at path edges, DrillBitSpinner uses radial mask instead of hard clip

Former-commit-id: 3aea27f3e17984634206ca817d074b18e712933e
This commit is contained in:
2026-05-11 21:31:49 +02:00
parent 079398239f
commit 74caea6854
11 changed files with 153 additions and 51 deletions

View File

@@ -8,24 +8,15 @@ import { motion } from 'framer-motion';
* Abstract animated drill head cross-section.
* Resembles an HDD tri-blade drill bit seen from the front.
*
* - 3 rotating cutting blades at 120° intervals
* - Outer halo ring
* - Inner core circle
* - Continuous rotation with optional pulse glow
*
* Zero layout impact — position it absolutely in its parent.
* The wrapping div uses a radial-gradient mask so it fades naturally
* into whatever background it's placed on — no hard edge clipping.
*/
interface DrillBitSpinnerProps {
/** Diameter in pixels */
size?: number;
/** Color of the drill elements */
color?: string;
/** Rotation duration in seconds */
duration?: number;
/** Overall opacity 01 */
opacity?: number;
/** Whether to show a pulse glow ring */
glow?: boolean;
className?: string;
}
@@ -44,8 +35,6 @@ export function DrillBitSpinner({
const bladeW = r * 0.18;
const coreR = r * 0.22;
// 3 blade tip positions at 120° intervals
// Each blade: a rounded rectangle swept from center outward
const blades = [0, 120, 240].map((deg) => {
const rad = (deg * Math.PI) / 180;
return {
@@ -58,7 +47,15 @@ export function DrillBitSpinner({
return (
<div
className={`relative pointer-events-none select-none ${className}`}
style={{ width: size, height: size, opacity }}
style={{
width: size,
height: size,
opacity,
// Radial gradient mask: the spinner fades out toward all edges.
// This prevents any hard clip when partially outside the container.
WebkitMaskImage: 'radial-gradient(circle at center, black 20%, transparent 70%)',
maskImage: 'radial-gradient(circle at center, black 20%, transparent 70%)',
}}
aria-hidden="true"
>
{/* Glow bloom (pulsing) */}
@@ -92,7 +89,6 @@ export function DrillBitSpinner({
{/* Three cutting blades */}
{blades.map((blade, i) => (
<g key={i} transform={`rotate(${blade.rotate} ${r} ${r})`}>
{/* Main blade body */}
<rect
x={r - bladeW / 2}
y={r - coreR}
@@ -101,9 +97,7 @@ export function DrillBitSpinner({
rx={bladeW / 2}
fill={color}
opacity={0.7}
transform={`rotate(0 ${r} ${r})`}
/>
{/* Blade tip accent */}
<circle
cx={r}
cy={r - coreR - bladeLen + bladeW / 2}
@@ -122,7 +116,7 @@ export function DrillBitSpinner({
opacity={0.5}
/>
{/* Center nozzle (mud port) */}
{/* Center nozzle */}
<circle cx={r} cy={r} r={coreR * 0.55} fill={color} opacity={0.85} />
<circle cx={r} cy={r} r={coreR * 0.22} fill="white" opacity={0.6} />
</motion.svg>