feat: hull traverse visualizer

This commit is contained in:
tresabhi committed 2025-04-20 22:51:53 -05:00
1 parent 4f47d6ce85
commit ed64ee8228
8 files changed
+160

No files matched your search

BIN
View File
Binary file not shown.
+10
View File
@@ -861,6 +861,16 @@
"tank_seo_title": "%s1 - Tier %s2 %s3 %s4 | %s5 Tankopedia | World of Tanks Blitz (WoTB)",
"tank_seo_description": "%s1 armor, statistics, equipment, provisions, and more. %s2 DPM, %s3hp alpha, %s4mm penetration, %s5kph top speed, %s6hp health.",
"visualizers": {
"rotator": {
"hull": "Hull",
"turret": "Turret",
"hard": "Hard",
"medium": "Medium",
"soft": "Soft"
}
},
"sandbox": {
"poses": {
"hull_down": "Hull down",
+1
View File
@@ -29,6 +29,7 @@
"js-cookie": "^3.0.5",
"markdown-to-jsx": "^7.5.0",
"nanostores": "^0.11.3",
"quicklime": "^1.2.0",
"react": "^18.3.1",
"react-device-detect": "^2.2.3",
"react-dom": "^18.3.1",
Binary file not shown.

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

@@ -0,0 +1,13 @@
@keyframes spin {
from {
transform: translate(-50%, -50%) rotate(0deg);
}
to {
transform: translate(-50%, -50%) rotate(360deg);
}
}
.hull-traverse-visualizer {
animation: spin linear infinite;
}
@@ -0,0 +1,133 @@
import { Card, Checkbox, Flex, Tabs, Text } from '@radix-ui/themes';
import { useRef, useState } from 'react';
import type { TankCharacteristics } from '../../../../../../../core/blitzkit/tankCharacteristics';
import { useLocale } from '../../../../../../../hooks/useLocale';
import './index.css';
interface HullTraverseVisualizerProps {
stats: TankCharacteristics;
}
interface HullTraverseVisualizerEventData {
hull: boolean;
turret: boolean;
}
type Terrain = 'Hard' | 'Medium' | 'Soft';
export function HullTraverseVisualizer({ stats }: HullTraverseVisualizerProps) {
const hull = useRef<HTMLDivElement>(null);
const turret = useRef<HTMLImageElement>(null);
const [terrain, setTerrain] = useState<Terrain>('Hard');
const [rotateHull, setRotateHull] = useState(true);
const [rotateTurret, setRotateTurret] = useState(true);
const { strings } = useLocale();
return (
<Card variant="classic" style={{ aspectRatio: '1 / 1' }}>
<div
ref={hull}
className="hull-traverse-visualizer"
style={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
animationDuration: `${
rotateHull ? 1 / (stats[`hullTraverse${terrain}Terrain`] / 360) : 0
}s`,
}}
>
<img
style={{
width: '12rem',
height: '12rem',
objectFit: 'contain',
filter: 'drop-shadow(0px 0px 4px black)',
}}
src="/assets/images/tankopedia/visualizers/hull-traverse/hull.png"
/>
<img
ref={turret}
className="hull-traverse-visualizer"
style={{
width: '27rem',
height: '27rem',
objectFit: 'contain',
position: 'absolute',
top: '50%',
left: '50%',
filter: 'drop-shadow(0px 0px 4px black)',
transform: 'translate(-50%, -50%)',
animationDuration: `${
rotateTurret ? 1 / (stats.turretTraverseSpeed / 360) : 0
}s`,
}}
src="/assets/images/tankopedia/visualizers/hull-traverse/turret.png"
/>
</div>
<Flex
position="absolute"
bottom="0"
left="50%"
style={{
transform: 'translateX(-50%)',
}}
>
<Tabs.Root
value={terrain}
onValueChange={(terrain) => setTerrain(terrain as Terrain)}
>
<Tabs.List>
<Tabs.Trigger value="Hard">
{strings.website.tools.tankopedia.visualizers.rotator.hard}
</Tabs.Trigger>
<Tabs.Trigger value="Medium">
{strings.website.tools.tankopedia.visualizers.rotator.medium}
</Tabs.Trigger>
<Tabs.Trigger value="Soft">
{strings.website.tools.tankopedia.visualizers.rotator.soft}
</Tabs.Trigger>
</Tabs.List>
</Tabs.Root>
</Flex>
<Flex
position="absolute"
top="4"
left="50%"
gap="5"
style={{
transform: 'translateX(-50%)',
userSelect: 'none',
}}
>
<Flex
align="center"
gap="2"
onClick={() => setRotateHull((state) => !state)}
style={{ cursor: 'pointer' }}
>
<Checkbox checked={rotateHull} />
<Text size="2">
{strings.website.tools.tankopedia.visualizers.rotator.hull}
</Text>
</Flex>
<Flex
align="center"
gap="2"
onClick={() => setRotateTurret((state) => !state)}
style={{ cursor: 'pointer' }}
>
<Checkbox checked={rotateTurret} />
<Text size="2">
{strings.website.tools.tankopedia.visualizers.rotator.turret}
</Text>
</Flex>
</Flex>
</Card>
);
}
@@ -31,6 +31,7 @@ import { useLocale } from '../../../../../hooks/useLocale';
import { useTankModelDefinition } from '../../../../../hooks/useTankModelDefinition';
import { Duel } from '../../../../../stores/duel';
import { TankopediaEphemeral } from '../../../../../stores/tankopediaEphemeral';
import { HullTraverseVisualizer } from './components/HullTraverseVisualizer';
import { Info } from './components/Info';
import { InfoWithDelta } from './components/InfoWithDelta';
@@ -753,6 +754,8 @@ export function Characteristics() {
indent
value="hullTraverseSoftTerrain"
/>
<HullTraverseVisualizer stats={stats} />
</Flex>
<Flex direction="column" gap="2">