feat: begennings of reload visuals

This commit is contained in:
tresabhi committed 2025-04-28 17:21:42 -05:00
1 parent aeaf52d3ac
commit d8c26ba24a
4 files changed
+199

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -24,6 +24,7 @@ import { Duel } from '../../../../../../stores/duel';
import type { StatsAcceptorProps } from './HullTraverseVisualizer';
import { Info } from './Info';
import { InfoWithDelta } from './InfoWithDelta';
import { ReloadVisualizer } from './ReloadVisualizer';
import { RicochetVisualizer } from './RicochetVisualizer';
import { StatsTableWrapper } from './StatsTableWrapper';
@@ -165,6 +166,8 @@ export function Firepower({ stats }: StatsAcceptorProps) {
value="intraClip"
/>
)}
<ReloadVisualizer stats={stats} />
<InfoWithDelta stats={stats} decimals={0} value="penetration" />
{typeof shell.penetration !== 'number' && (
<>
@@ -0,0 +1,61 @@
import { Box, Flex } from '@radix-ui/themes';
import type { QuicklimeCallback } from 'quicklime';
import { useEffect, useRef } from 'react';
import { reloadUpdate, type ReloadUpdateData } from '..';
import { Var } from '../../../../../../../../core/radix/var';
import type { StatsAcceptorProps } from '../../HullTraverseVisualizer';
interface ShellProps {
index: number;
}
export function Shell({ index, stats }: ShellProps & StatsAcceptorProps) {
const bar = useRef<HTMLDivElement>(null!);
useEffect(() => {
const handleReloadUpdate: QuicklimeCallback<ReloadUpdateData> = ({
data,
}) => {
bar.current.style.width = `${data.shells[index] * 100}%`;
};
reloadUpdate.on(handleReloadUpdate);
return () => {
reloadUpdate.off(handleReloadUpdate);
};
}, []);
return (
<Box
style={{
width: '100%',
position: 'absolute',
top: '50%',
left: '50%',
transform: `translate(-50%, -50%) rotate(${(index - Math.floor(stats.shells / 2)) * 10}deg)`,
}}
>
<Flex
justify="end"
style={{
position: 'absolute',
left: '50%',
marginLeft: 'calc(25% + 2rem)',
width: '1.25rem',
height: '0.5rem',
borderRadius: '0.25rem',
overflow: 'hidden',
outline: `1px solid ${Var('jade-6')}`,
}}
>
<Box
ref={bar}
style={{
background: Var('jade-9'),
}}
/>
</Flex>
</Box>
);
}
@@ -0,0 +1,135 @@
import { Box, Card } from '@radix-ui/themes';
import { times } from 'lodash-es';
import { Quicklime, type QuicklimeCallback } from 'quicklime';
import { useEffect, useRef } from 'react';
import { Var } from '../../../../../../../core/radix/var';
import type { StatsAcceptorProps } from '../HullTraverseVisualizer';
import { Shell } from './components/Shell';
export interface ReloadUpdateData {
reload: number;
shells: number[];
}
export const reloadUpdate = new Quicklime<ReloadUpdateData>();
export function ReloadVisualizer({ stats }: StatsAcceptorProps) {
const reloadCircle = useRef<HTMLDivElement>(null!);
const reloadCore = useRef<HTMLDivElement>(null!);
const reloadGlow = useRef<HTMLDivElement>(null!);
const size = `${stats.shells === 1 ? 66 : 58}%`;
useEffect(() => {
let cancel = false;
function frame() {
const now = Date.now() / 1000;
const t = now % stats.shellReload!;
const x = t / stats.shellReload!;
reloadUpdate.dispatch({
reload: x,
shells: Array(stats.shells).fill(x),
});
if (!cancel) requestAnimationFrame(frame);
}
frame();
return () => {
cancel = true;
};
}, [stats]);
useEffect(() => {
const handleReloadUpdate: QuicklimeCallback<ReloadUpdateData> = ({
data,
}) => {
const reloadAngle = data.reload * 2 * Math.PI;
reloadCircle.current.style.background = `conic-gradient(${Var('amber-9')} 0 ${reloadAngle}rad, ${Var('red-7')} ${reloadAngle}rad)`;
reloadCore.current.style.background = `conic-gradient(${Var('amber-3')} 0 ${reloadAngle}rad, ${Var('red-2')} ${reloadAngle}rad)`;
reloadGlow.current.style.background = `conic-gradient(${Var('amber-8')} 0 ${reloadAngle}rad, transparent ${reloadAngle}rad)`;
};
reloadUpdate.on(handleReloadUpdate);
return () => {
reloadUpdate.off(handleReloadUpdate);
};
}, []);
return (
<Card variant="classic" mb="6" style={{ aspectRatio: '1 / 1' }}>
<Box
p="4"
position="absolute"
top="50%"
left="50%"
width={size}
height={size}
className="reload"
ref={reloadGlow}
style={{
transform: 'translate(-50%, -50%)',
borderRadius: '50%',
filter: 'blur(0.5rem)',
}}
/>
<Box
p="1"
position="absolute"
top="50%"
left="50%"
width={size}
height={size}
className="reload"
ref={reloadCircle}
style={{
transform: 'translate(-50%, -50%)',
borderRadius: '50%',
background: Var('red-7'),
}}
>
<Box
ref={reloadCore}
style={{
backgroundColor: Var('red-2'),
borderRadius: '50%',
}}
width="100%"
height="100%"
overflow="hidden"
>
<Box
style={{
width: '100%',
height: '100%',
background: `radial-gradient(${Var('gray-3')} 25%, transparent)`,
}}
/>
</Box>
</Box>
<img
src="/assets/images/tankopedia/visualizers/reload/caret.png"
style={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translateX(-50%)',
width: '10%',
height: '10%',
}}
/>
{times(stats.shells, (index) => (
<Shell stats={stats} index={index} key={index} />
))}
</Card>
);
}