Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | 3x 30x 30x 30x 30x 30x 30x 30x 30x 30x 3x | /**
* ConsciousnessBlur Component - Visual effect for consciousness impairment
*
* Applies a blur effect to the screen that intensifies as consciousness decreases.
* Uses CSS backdrop-filter for performance-efficient blur rendering.
*
* NOTE: This component is rendered OUTSIDE the Canvas as part of the HTML overlay.
* It does NOT use Html from drei - it's a standard React component.
*
* @module components/combat/ConsciousnessBlur
* @category Combat UI
* @korean 의식흐림효과
*/
import React, { useMemo } from "react";
export interface ConsciousnessBlurProps {
/**
* Current consciousness level (0-100)
* 100 = fully conscious, 0 = unconscious
* @korean 의식수준
*/
readonly consciousness: number;
/**
* Mobile responsive mode (reduced blur strength)
* @korean 모바일여부
*/
readonly isMobile: boolean;
}
/**
* ConsciousnessBlur - Screen blur effect based on consciousness level
*
* Renders a fullscreen overlay with blur effect that intensifies as
* consciousness decreases. Only visible when consciousness is 90 or below.
* Optimized for 60fps with CSS backdrop-filter.
*
* Accessibility behavior:
* - Purely decorative visual effect
* - Marked with aria-hidden="true" and excluded from the accessibility tree
* - Does not announce consciousness level to screen readers
* (use a separate, dedicated announcement channel if needed)
*
* @example
* ```tsx
* <ConsciousnessBlur consciousness={45} isMobile={false} />
* // No render if consciousness > 90
* <ConsciousnessBlur consciousness={95} isMobile={false} />
* ```
*/
export const ConsciousnessBlur: React.FC<ConsciousnessBlurProps> = ({
consciousness,
isMobile,
}) => {
const blurStyle = useMemo(() => {
// Clamp consciousness to 0-100 range
const clampedConsciousness = Math.max(0, Math.min(100, consciousness));
// Calculate blur amount (inverse of consciousness)
// 100 consciousness = 0px blur, 0 consciousness = 12px blur (8px on mobile)
const maxBlur = isMobile ? 8 : 12;
const blurAmount = Math.round(
((100 - clampedConsciousness) / 100) * maxBlur
);
// Also add slight opacity darkening for dramatic effect
const opacity = Math.pow((100 - clampedConsciousness) / 100, 2) * 0.3;
// Don't apply blur if consciousness is high (> 90)
Eif (clampedConsciousness > 90) {
return null;
}
return {
position: "fixed" as const,
inset: 0,
pointerEvents: "none" as const,
backdropFilter: `blur(${blurAmount}px)`,
WebkitBackdropFilter: `blur(${blurAmount}px)`, // Safari support
backgroundColor: `rgba(0, 0, 0, ${opacity})`,
transition:
"backdrop-filter 0.5s ease-out, background-color 0.5s ease-out",
zIndex: 60, // Above game content but below HUD
};
}, [consciousness, isMobile]);
// Don't render if consciousness is very high
Eif (consciousness > 90 || !blurStyle) {
return null;
}
// Decorative visual overlay; aria-hidden with no live region or additional ARIA roles needed
return (
<div
data-testid="consciousness-blur"
style={blurStyle}
aria-hidden="true"
/>
);
};
ConsciousnessBlur.displayName = "ConsciousnessBlur";
|