From 5fa4d3b24263421d2de2a5434f011cb6464417fe Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com>
Date: Tue, 28 Apr 2026 16:17:40 -0500
Subject: [PATCH 1/7] remove aeson
---
.../components/Equalizer.tsx | 31 -------------------
1 file changed, 31 deletions(-)
diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Equalizer.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Equalizer.tsx
index f49200157..1ec26568a 100644
--- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Equalizer.tsx
+++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Equalizer.tsx
@@ -70,37 +70,6 @@ export function Equalizer() {
-
-
-
-
-
- Brought to you by{" "}
-
{" "}
- WoTB News
-
-
-
-
-
-
- This feature was brought to you early, ahead of the release of the
- game mode, thanks to{" "}
-
- WoTB News
-
- .
-
-
-
);
}
From 3edf4a25bee45ca73ba8e710e8d2591c62ec80d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com>
Date: Sun, 10 May 2026 21:55:33 -0500
Subject: [PATCH 2/7] impossible inspect element
---
packages/website/src/components/Guesser.tsx | 24 +++++++++++++++------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/packages/website/src/components/Guesser.tsx b/packages/website/src/components/Guesser.tsx
index 62ff27553..292025229 100644
--- a/packages/website/src/components/Guesser.tsx
+++ b/packages/website/src/components/Guesser.tsx
@@ -58,12 +58,14 @@ export function Guesser() {
const [results, setResults] = useState(null);
const [selected, setSelected] = useState(null);
const tiers = Guess.use((state) => state.tiers);
+ const status = useRef(null);
const requestSearch = useCallback(() => {
setSelected(null);
setSearching(true);
search();
}, []);
+
const search = useCallback(
debounce(() => {
if (!input.current) return;
@@ -92,6 +94,20 @@ export function Guesser() {
if (guessState !== GuessState.NotGuessed) setSelected(null);
}, [guessState]);
+ useEffect(() => {
+ const interval = setInterval(() => {
+ if (!status.current) return;
+
+ status.current.innerText = literals(strings.website.tools.guess.stats, {
+ correct: correctGuesses,
+ total: totalGuesses,
+ streak: streak,
+ });
+ }, 1000 / 60);
+
+ return () => clearInterval(interval);
+ }, [correctGuesses, totalGuesses, streak]);
+
return (
-
- {literals(strings.website.tools.guess.stats, {
- correct: correctGuesses,
- total: totalGuesses,
- streak: streak,
- })}
-
+
From 042a1afa74209c2abcdb87066b61e8eaad6144b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com>
Date: Mon, 11 May 2026 16:18:54 -0500
Subject: [PATCH 3/7] remove cache from useModel
---
packages/website/src/hooks/useModel.ts | 30 ++++++++------------------
1 file changed, 9 insertions(+), 21 deletions(-)
diff --git a/packages/website/src/hooks/useModel.ts b/packages/website/src/hooks/useModel.ts
index 8f6d8a411..83bfc7cfa 100644
--- a/packages/website/src/hooks/useModel.ts
+++ b/packages/website/src/hooks/useModel.ts
@@ -3,28 +3,16 @@ import { type ObjectMap, useLoader } from "@react-three/fiber";
import { Mesh, MeshStandardMaterial } from "three";
import { type GLTF, GLTFLoader } from "three-stdlib";
-const cache: Record<
- number,
- {
- gltf: GLTF & ObjectMap;
- hasPbr: boolean;
- }
-> = {};
-
export function useModel(id: number) {
const gltf = useLoader(GLTFLoader, asset(`3d/tanks/models/${id}.glb`));
- if (!cache[id]) {
- cache[id] = {
- gltf,
- hasPbr: Object.values(gltf.nodes).some(
- (node) =>
- node instanceof Mesh &&
- node.material instanceof MeshStandardMaterial &&
- node.material.roughnessMap !== null
- ),
- };
- }
-
- return cache[id];
+ return {
+ gltf,
+ hasPbr: Object.values(gltf.nodes).some(
+ (node) =>
+ node instanceof Mesh &&
+ node.material instanceof MeshStandardMaterial &&
+ node.material.roughnessMap !== null
+ ),
+ };
}
From 0b2e322112effa3ec9b215556524e07b3c551121 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com>
Date: Mon, 11 May 2026 17:14:22 -0500
Subject: [PATCH 4/7] disbale low tiers
---
packages/website/src/components/Guesser.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/website/src/components/Guesser.tsx b/packages/website/src/components/Guesser.tsx
index 292025229..4f6f6e51a 100644
--- a/packages/website/src/components/Guesser.tsx
+++ b/packages/website/src/components/Guesser.tsx
@@ -322,7 +322,7 @@ export function Guesser() {
? GuessState.Correct
: GuessState.Incorrect;
draft.totalGuesses++;
- draft.correctGuesses += correct ? 1 : 0;
+ draft.correctGuesses += correct && draft.tiers.length === 10 ? 1 : 0;
draft.streak = correct ? draft.streak + 1 : 0;
});
} else {
From 4f42a31f53d4637532a85e2c0e2422dceab70538 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com>
Date: Mon, 11 May 2026 17:52:23 -0500
Subject: [PATCH 5/7] Reduce interval timing from 60fps to 200ms
---
packages/website/src/components/Guesser.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/website/src/components/Guesser.tsx b/packages/website/src/components/Guesser.tsx
index 4f6f6e51a..27c7915f0 100644
--- a/packages/website/src/components/Guesser.tsx
+++ b/packages/website/src/components/Guesser.tsx
@@ -103,7 +103,7 @@ export function Guesser() {
total: totalGuesses,
streak: streak,
});
- }, 1000 / 60);
+ }, 1000 / 200);
return () => clearInterval(interval);
}, [correctGuesses, totalGuesses, streak]);
From 100c7391fbb81c79d897375bb4d13c4908b2912b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com>
Date: Tue, 12 May 2026 17:54:50 -0500
Subject: [PATCH 6/7] dispose models on unload
---
packages/website/src/hooks/useArmor.ts | 34 ++++++------
packages/website/src/hooks/useDispose.ts | 67 ++++++++++++++++++++++++
packages/website/src/hooks/useModel.ts | 12 +++--
3 files changed, 90 insertions(+), 23 deletions(-)
create mode 100644 packages/website/src/hooks/useDispose.ts
diff --git a/packages/website/src/hooks/useArmor.ts b/packages/website/src/hooks/useArmor.ts
index e1a5f05a6..d697bd0ba 100644
--- a/packages/website/src/hooks/useArmor.ts
+++ b/packages/website/src/hooks/useArmor.ts
@@ -1,23 +1,19 @@
-import { asset } from '@blitzkit/core';
-import { type ObjectMap, useLoader } from '@react-three/fiber';
-import { type GLTF, GLTFLoader } from 'three-stdlib';
-
-const cache: Record<
- number,
- { gltf: GLTF & ObjectMap; hasDynamicArmor: boolean }
-> = {};
+import { asset } from "@blitzkit/core";
+import { useLoader } from "@react-three/fiber";
+import { GLTFLoader } from "three-stdlib";
+import { useDispose } from "./useDispose";
export function useArmor(id: number) {
- const gltf = useLoader(GLTFLoader, asset(`3d/tanks/armor/${id}.glb`));
+ const path = asset(`3d/tanks/armor/${id}.glb`);
+ const gltf = useLoader(GLTFLoader, path);
- if (!cache[id]) {
- cache[id] = {
- gltf,
- hasDynamicArmor: Object.values(gltf.nodes).some(
- (node) =>
- node.name.includes('state_00') || node.name.includes('state_01'),
- ),
- };
- }
- return cache[id];
+ useDispose(gltf, path);
+
+ return {
+ gltf,
+ hasDynamicArmor: Object.values(gltf.nodes).some(
+ (node) =>
+ node.name.includes("state_00") || node.name.includes("state_01"),
+ ),
+ };
}
diff --git a/packages/website/src/hooks/useDispose.ts b/packages/website/src/hooks/useDispose.ts
new file mode 100644
index 000000000..dffe2dc81
--- /dev/null
+++ b/packages/website/src/hooks/useDispose.ts
@@ -0,0 +1,67 @@
+import { useLoader } from "@react-three/fiber";
+import { useEffect } from "react";
+import { Cache } from "three";
+import { GLTFLoader } from "three-stdlib";
+
+export function useDispose(gltf: any, path: string) {
+ useEffect(() => {
+ return () => {
+ const disposedGeometries = new Set();
+ const disposedMaterials = new Set();
+ const disposedTextures = new Set();
+
+ gltf.scene.traverse((obj: any) => {
+ if (obj.geometry) {
+ const geometry = obj.geometry;
+
+ if (!disposedGeometries.has(geometry.uuid)) {
+ disposedGeometries.add(geometry.uuid);
+ geometry.dispose();
+ }
+ }
+
+ if (obj.material) {
+ const materials = Array.isArray(obj.material)
+ ? obj.material
+ : [obj.material];
+
+ for (const material of materials) {
+ if (!disposedMaterials.has(material.uuid)) {
+ disposedMaterials.add(material.uuid);
+
+ for (const key in material) {
+ const value = material[key];
+
+ if (
+ value &&
+ value.isTexture &&
+ !disposedTextures.has(value.uuid)
+ ) {
+ disposedTextures.add(value.uuid);
+ }
+ }
+
+ for (const key in material) {
+ const value = material[key];
+
+ if (value && value.isTexture) {
+ value.source.data.close();
+ value.dispose();
+ }
+ }
+
+ material.dispose();
+ }
+ }
+ }
+
+ if (obj.skeleton) {
+ obj.skeleton.dispose?.();
+ }
+ });
+
+ useLoader.clear(GLTFLoader, path);
+ Cache.remove(path);
+ };
+ }, [gltf, path]);
+}
diff --git a/packages/website/src/hooks/useModel.ts b/packages/website/src/hooks/useModel.ts
index 83bfc7cfa..c8d532bd5 100644
--- a/packages/website/src/hooks/useModel.ts
+++ b/packages/website/src/hooks/useModel.ts
@@ -1,10 +1,14 @@
import { asset } from "@blitzkit/core";
-import { type ObjectMap, useLoader } from "@react-three/fiber";
+import { useLoader } from "@react-three/fiber";
import { Mesh, MeshStandardMaterial } from "three";
-import { type GLTF, GLTFLoader } from "three-stdlib";
+import { GLTFLoader } from "three-stdlib";
+import { useDispose } from "./useDispose";
export function useModel(id: number) {
- const gltf = useLoader(GLTFLoader, asset(`3d/tanks/models/${id}.glb`));
+ const path = asset(`3d/tanks/models/${id}.glb`);
+ const gltf = useLoader(GLTFLoader, path);
+
+ useDispose(gltf, path);
return {
gltf,
@@ -12,7 +16,7 @@ export function useModel(id: number) {
(node) =>
node instanceof Mesh &&
node.material instanceof MeshStandardMaterial &&
- node.material.roughnessMap !== null
+ node.material.roughnessMap !== null,
),
};
}
From 2f745a16d11141dac87210c73f208ba2e05405de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com>
Date: Tue, 12 May 2026 18:08:02 -0500
Subject: [PATCH 7/7] clean up
---
packages/website/src/hooks/useDispose.ts | 85 ++++++++++--------------
1 file changed, 34 insertions(+), 51 deletions(-)
diff --git a/packages/website/src/hooks/useDispose.ts b/packages/website/src/hooks/useDispose.ts
index dffe2dc81..2ff4e3685 100644
--- a/packages/website/src/hooks/useDispose.ts
+++ b/packages/website/src/hooks/useDispose.ts
@@ -1,62 +1,45 @@
-import { useLoader } from "@react-three/fiber";
+import { useLoader, type ObjectMap } from "@react-three/fiber";
import { useEffect } from "react";
-import { Cache } from "three";
-import { GLTFLoader } from "three-stdlib";
+import { Cache, Group, Mesh, MeshStandardMaterial, Object3D } from "three";
+import { GLTFLoader, type GLTF } from "three-stdlib";
-export function useDispose(gltf: any, path: string) {
+export function useDispose(gltf: GLTF & ObjectMap, path: string) {
useEffect(() => {
return () => {
- const disposedGeometries = new Set();
- const disposedMaterials = new Set();
- const disposedTextures = new Set();
+ gltf.scene.traverse((object) => {
+ if (object instanceof Mesh) {
+ if (object.material instanceof MeshStandardMaterial) {
+ const maps = [
+ object.material.map,
+ object.material.aoMap,
+ object.material.envMap,
+ object.material.bumpMap,
+ object.material.alphaMap,
+ object.material.lightMap,
+ object.material.normalMap,
+ object.material.emissiveMap,
+ object.material.roughnessMap,
+ object.material.metalnessMap,
+ object.material.displacementMap,
+ ];
- gltf.scene.traverse((obj: any) => {
- if (obj.geometry) {
- const geometry = obj.geometry;
+ for (const map of maps) {
+ if (!map) continue;
- if (!disposedGeometries.has(geometry.uuid)) {
- disposedGeometries.add(geometry.uuid);
- geometry.dispose();
- }
- }
-
- if (obj.material) {
- const materials = Array.isArray(obj.material)
- ? obj.material
- : [obj.material];
-
- for (const material of materials) {
- if (!disposedMaterials.has(material.uuid)) {
- disposedMaterials.add(material.uuid);
-
- for (const key in material) {
- const value = material[key];
-
- if (
- value &&
- value.isTexture &&
- !disposedTextures.has(value.uuid)
- ) {
- disposedTextures.add(value.uuid);
- }
- }
-
- for (const key in material) {
- const value = material[key];
-
- if (value && value.isTexture) {
- value.source.data.close();
- value.dispose();
- }
- }
-
- material.dispose();
+ map.source.data.close();
+ map.dispose();
}
- }
- }
- if (obj.skeleton) {
- obj.skeleton.dispose?.();
+ object.material.dispose();
+ } else {
+ throw new TypeError(
+ `Unexpected material type: ${object.material.type}`,
+ );
+ }
+ } else if (object instanceof Group || object instanceof Object3D) {
+ // traverse will get children
+ } else {
+ throw new TypeError(`Unexpected object type: ${object}`);
}
});