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}`); } });