From 406d70b5b74d7ec3b32db7c71d53663cc2b0810d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Mon, 22 Jun 2026 09:38:55 -0500 Subject: [PATCH 01/32] New translations en.json (Ukrainian) (#250) [ci skip] --- packages/i18n/strings/uk.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/i18n/strings/uk.json b/packages/i18n/strings/uk.json index e30623ee7..673289de1 100644 --- a/packages/i18n/strings/uk.json +++ b/packages/i18n/strings/uk.json @@ -876,7 +876,7 @@ "yaw": "Yaw", "pitch": "Pitch", "min": "Min", - "max": "Max" + "max": "Макс" } }, "sandbox": { @@ -908,7 +908,7 @@ "normalization": "Нормалізація", "ricochet": "Рикошет", "explosion_radius": "Радіус розльоту уламків", - "exit": "Exit", + "exit": "Вийти", "reset": "Reset" }, "advanced": "Advanced highlighting", @@ -923,7 +923,7 @@ }, "status": { "penetration": "{damage}hp penetration", - "blocked": "Blocked", + "blocked": "Заблоковано", "ricochet": "Рикошет", "splash": "{damage}hp splash" }, From 2ffe3fc0064d61ad45f15be3f94fe401beb4ff41 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:28:02 -0500 Subject: [PATCH 02/32] set up patches --- .github/workflows/assets.yml | 4 ++ docs/changelogs/1.30.4.md | 5 ++ package.json | 4 +- packages/scripts/src/applyPatches.ts | 31 ++++++------ packages/scripts/src/buildAssets/constants.ts | 5 ++ packages/scripts/src/core/vfs/mixed.ts | 49 +++++++++++++++++++ 6 files changed, 80 insertions(+), 18 deletions(-) create mode 100644 docs/changelogs/1.30.4.md create mode 100644 packages/scripts/src/core/vfs/mixed.ts diff --git a/.github/workflows/assets.yml b/.github/workflows/assets.yml index 222b45e9d..1cb21a5a1 100644 --- a/.github/workflows/assets.yml +++ b/.github/workflows/assets.yml @@ -73,10 +73,14 @@ jobs: with: repo-token: ${{ secrets.GH_TOKEN }} - uses: oven-sh/setup-bun@v2 + - run: bun run setup - name: AppArmor hack run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns + - name: Install patches + run: bun run setup:patches + - name: Build assets run: bun run build:assets --all-targets --source=${{ github.event.inputs.asset_source || 'steam:444200/444202' }} diff --git a/docs/changelogs/1.30.4.md b/docs/changelogs/1.30.4.md new file mode 100644 index 000000000..166a121cb --- /dev/null +++ b/docs/changelogs/1.30.4.md @@ -0,0 +1,5 @@ +# BlitzKit 1.30.3 + +## Fixes + +- BlitzKit now correctly implements minor WoTB updates diff --git a/package.json b/package.json index 3fa646324..4445a6b58 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blitzkit", - "version": "1.30.3", + "version": "1.30.4", "license": "BlitzKit License", "private": true, "scripts": { @@ -21,7 +21,7 @@ "dev": "bun run dev:website", "dev:api": "bun --filter=@blitzkit/api run dev", "setup:depotdownloader": "bun --filter=@blitzkit/scripts run setup:depotdownloader", - "setup:patches": "bun --filter=@blitzkit/scripts run setup:patches", + "setup:patches": "cd packages/scripts && bun run setup:patches", "start:website": "bun --filter=@blitzkit/website run start", "host:docs": "vitepress preview docs", "lint": "tsc", diff --git a/packages/scripts/src/applyPatches.ts b/packages/scripts/src/applyPatches.ts index 7064ce932..5128b3e2d 100644 --- a/packages/scripts/src/applyPatches.ts +++ b/packages/scripts/src/applyPatches.ts @@ -4,7 +4,7 @@ import { mkdir, writeFile } from "fs/promises"; import { parse as parsePath } from "path"; import ProgressBar from "progress"; import { parse as parseYaml, stringify as stringifyYaml } from "yaml"; -import { vfs } from "./buildAssets/constants"; +import { PATCHES_ROOT, vfs } from "./buildAssets/constants"; import { writeDVPL } from "./core/blitz/writeDVPL"; const versionTextFile = await vfs.text(`Data/version.txt`); @@ -20,8 +20,8 @@ let patchIndex = 1; while (true) { const response = await fetch( `${assertSecret( - import.meta.env.WOTB_DLC_CDN - )}/dlc/s${currentVersion}_${patchIndex}.yaml` + import.meta.env.WOTB_DLC_CDN, + )}/dlc/s${currentVersion}_${patchIndex}.yaml`, ); if (response.status === 200) { @@ -29,18 +29,18 @@ while (true) { const data = parseYaml(await response.text()); const dvpm = await fetch( - `${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${data.dx11}` + `${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${data.dx11}`, ).then((response) => response.arrayBuffer()); const dvpd = await fetch( `${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${data.dx11.replace( ".dvpm", - ".dvpd" - )}` + ".dvpd", + )}`, ).then((response) => response.arrayBuffer()); const files = await dvp(dvpm, dvpd); const bar = new ProgressBar( `Patching ${files.length} files :bar`, - files.length + files.length, ); for (const { path, data } of files) { @@ -49,7 +49,7 @@ while (true) { const { dir } = parsePath(path); try { - await mkdir(`Data/${dir}`, { recursive: true }); + await mkdir(`${PATCHES_ROOT}/Data/${dir}`, { recursive: true }); } catch (error) { console.warn(`Failed to make directory "${dir}"`); } @@ -58,8 +58,8 @@ while (true) { const buffer = Buffer.from(data); await writeFile( - `Data/${path}${isDvpl ? "" : ".dvpl"}`, - new Uint8Array(isDvpl ? buffer : writeDVPL(buffer)) + `${PATCHES_ROOT}/Data/${path}${isDvpl ? "" : ".dvpl"}`, + new Uint8Array(isDvpl ? buffer : writeDVPL(buffer)), ); bar.tick(); @@ -71,18 +71,17 @@ while (true) { const localizationsResponse = await fetch( `${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${ data.dynamicContentLocalizationsDir - }/en.yaml` + }/en.yaml`, ); const newStrings = parseYaml(await localizationsResponse.text()); - const oldStrings = await vfs.yaml>( - `Data/Strings/en.yaml` - ); + const oldStrings = + await vfs.yaml>(`Data/Strings/en.yaml`); const patchedStrings = { ...oldStrings, ...newStrings }; const patchedContent = stringifyYaml(patchedStrings); await writeFile( - `Data/Strings/en.yaml`, - new Uint8Array(writeDVPL(Buffer.from(patchedContent))) + `${PATCHES_ROOT}/Data/Strings/en.yaml`, + new Uint8Array(writeDVPL(Buffer.from(patchedContent))), ); } diff --git a/packages/scripts/src/buildAssets/constants.ts b/packages/scripts/src/buildAssets/constants.ts index 7516210da..e6c37836e 100644 --- a/packages/scripts/src/buildAssets/constants.ts +++ b/packages/scripts/src/buildAssets/constants.ts @@ -3,6 +3,9 @@ import { AbstractVFS } from "../core/vfs/abstract"; import { LocalVFS } from "../core/vfs/local"; import { SteamVFS } from "../core/vfs/steam"; import { ZipVFS } from "../core/vfs/zip"; +import { MixedVFS } from "../core/vfs/mixed"; + +export const PATCHES_ROOT = "../../temp/patches"; const steamPattern = /steam:(\d+)\/(\d+)/; const zipPattern = /zip:(.+)/; @@ -35,4 +38,6 @@ if (!source) { throw new Error("No valid source specified"); } +resolved = new MixedVFS([new LocalVFS(PATCHES_ROOT), resolved]); + export const vfs = resolved; diff --git a/packages/scripts/src/core/vfs/mixed.ts b/packages/scripts/src/core/vfs/mixed.ts new file mode 100644 index 000000000..1d3358ddb --- /dev/null +++ b/packages/scripts/src/core/vfs/mixed.ts @@ -0,0 +1,49 @@ +import { AbstractVFS } from "./abstract"; + +export class MixedVFS extends AbstractVFS { + constructor(private vfses: AbstractVFS[]) { + super(); + } + + async init() { + for (const vfs of this.vfses) { + await vfs.init(); + } + + return this; + } + + dispose() { + for (const vfs of this.vfses) { + vfs.dispose(); + } + } + + async has(path: string) { + for (const vfs of this.vfses) { + if (await vfs.has(path)) return true; + } + + return false; + } + + async raw(path: string) { + for (const vfs of this.vfses) { + if (await vfs.has(path)) return await vfs.raw(path); + } + + throw new Error(`File not found: ${path}`); + } + + async dir(path: string) { + const files = new Set(); + + for (const vfs of this.vfses) { + for (const file of await vfs.dir(path)) { + files.add(file); + } + } + + return Array.from(files); + } +} From f5f170bccae59bdeac82aa1d91b8336b0b3f2872 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:32:26 -0500 Subject: [PATCH 03/32] switch to clean dava --- packages/closed | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/closed b/packages/closed index 5b4a85d50..0063700b9 160000 --- a/packages/closed +++ b/packages/closed @@ -1 +1 @@ -Subproject commit 5b4a85d503ca2bec859f856b26762c8fea33d545 +Subproject commit 0063700b97080f9eb4857b0a03d140be736d06a9 From 394f28e6edec6470e96d5361b2cf022194089818 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:33:52 -0500 Subject: [PATCH 04/32] remove proxyclient --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4445a6b58..3871a2935 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "build:reviews": "cd packages/scripts && bun build:reviews", "build:ids": "cd packages/scripts && bun build:ids", "prunestrings": "cd packages/scripts && bun prunestrings", - "setup": "bun install && bun run build:prisma && bun run build:proxyclient", + "setup": "bun install && bun run build:prisma", "patchnotes": "cd packages/scripts && bun run patchnotes" }, "type": "module", From e8325df832fc1a8e660a5c2e9506970dd254d8e4 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:44:03 -0500 Subject: [PATCH 05/32] lz4js --- bun.lock | 4 +--- package.json | 1 + packages/closed | 2 +- packages/core/package.json | 1 - packages/scripts/package.json | 1 - 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/bun.lock b/bun.lock index e144a01a2..750640f04 100644 --- a/bun.lock +++ b/bun.lock @@ -6,6 +6,7 @@ "name": "blitzkit", "dependencies": { "@prisma/client": "^6.18.0", + "lz4js": "^0.2.0", "prisma": "^6.18.0", "sharp": "^0.34.5", "typescript": "^5.9.3", @@ -56,7 +57,6 @@ "@bufbuild/protobuf": "^2.10.0", "@types/lz4js": "^0.2.1", "@types/pako": "^2.0.4", - "lz4js": "^0.2.0", "pako": "^2.1.0", }, }, @@ -78,7 +78,6 @@ "dotenv": "^17.2.2", "fast-xml-parser": "^5.3.2", "lodash-es": "^4.17.21", - "lz4js": "^0.2.0", "pickleparser": "^0.2.1", "protobufjs": "^7.5.4", "three": "^0.180.0", @@ -118,7 +117,6 @@ "fast-xml-parser": "^5.2.5", "googleapis": "^162.0.0", "lodash-es": "^4.17.21", - "lz4js": "^0.2.0", "progress": "^2.0.3", "puppeteer": "^24.22.3", "sharp": "^0.34.4", diff --git a/package.json b/package.json index 3871a2935..295710449 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ ], "dependencies": { "@prisma/client": "^6.18.0", + "lz4js": "^0.2.0", "prisma": "^6.18.0", "sharp": "^0.34.5", "typescript": "^5.9.3" diff --git a/packages/closed b/packages/closed index 0063700b9..16fe18d97 160000 --- a/packages/closed +++ b/packages/closed @@ -1 +1 @@ -Subproject commit 0063700b97080f9eb4857b0a03d140be736d06a9 +Subproject commit 16fe18d9737bd35d23dc25b6032a14a02f6f00bf diff --git a/packages/core/package.json b/packages/core/package.json index 32d782ce9..7f5046a56 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -19,7 +19,6 @@ "dotenv": "^17.2.2", "fast-xml-parser": "^5.3.2", "lodash-es": "^4.17.21", - "lz4js": "^0.2.0", "pickleparser": "^0.2.1", "protobufjs": "^7.5.4", "three": "^0.180.0", diff --git a/packages/scripts/package.json b/packages/scripts/package.json index 3e3d830c1..8e788dc2d 100644 --- a/packages/scripts/package.json +++ b/packages/scripts/package.json @@ -24,7 +24,6 @@ "fast-xml-parser": "^5.2.5", "googleapis": "^162.0.0", "lodash-es": "^4.17.21", - "lz4js": "^0.2.0", "progress": "^2.0.3", "puppeteer": "^24.22.3", "sharp": "^0.34.4", From 88290ec1abdeae6f498d26ad6329211d3c581f6d Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:54:01 -0500 Subject: [PATCH 06/32] garbage code --- bun.lock | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bun.lock b/bun.lock index 750640f04..5db46834c 100644 --- a/bun.lock +++ b/bun.lock @@ -57,6 +57,7 @@ "@bufbuild/protobuf": "^2.10.0", "@types/lz4js": "^0.2.1", "@types/pako": "^2.0.4", + "lz4js": "^0.2.0", "pako": "^2.1.0", }, }, diff --git a/package.json b/package.json index 295710449..1597733ae 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "dev": "bun run dev:website", "dev:api": "bun --filter=@blitzkit/api run dev", "setup:depotdownloader": "bun --filter=@blitzkit/scripts run setup:depotdownloader", - "setup:patches": "cd packages/scripts && bun run setup:patches", + "setup:patches": "mkdir -p packages/closed/node_modules && ln -sf ../../../node_modules/lz4js packages/closed/node_modules/lz4js && cd packages/scripts && bun run setup:patches", "start:website": "bun --filter=@blitzkit/website run start", "host:docs": "vitepress preview docs", "lint": "tsc", From 1bde50e0a3b257e2eeb10280b28ab850c3465002 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:54:09 -0500 Subject: [PATCH 07/32] garbage code --- packages/closed | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/closed b/packages/closed index 16fe18d97..f89f0e077 160000 --- a/packages/closed +++ b/packages/closed @@ -1 +1 @@ -Subproject commit 16fe18d9737bd35d23dc25b6032a14a02f6f00bf +Subproject commit f89f0e0772d5c851151d53ea78e05bfa16d8ea8d From 1e4d00ea348374172330ebb90ec1341c2d0c2d9d Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:55:39 -0500 Subject: [PATCH 08/32] source --- .github/workflows/assets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/assets.yml b/.github/workflows/assets.yml index 1cb21a5a1..f71f06861 100644 --- a/.github/workflows/assets.yml +++ b/.github/workflows/assets.yml @@ -80,7 +80,7 @@ jobs: run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns - name: Install patches - run: bun run setup:patches + run: bun run setup:patches --source=${{ github.event.inputs.asset_source || 'steam:444200/444202' }} - name: Build assets run: bun run build:assets --all-targets --source=${{ github.event.inputs.asset_source || 'steam:444200/444202' }} From 1df2e818befda7de5b19a5ac7778fa1d27cdb3ba Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 22 Jun 2026 19:57:41 -0500 Subject: [PATCH 09/32] dirs --- packages/scripts/src/applyPatches.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/scripts/src/applyPatches.ts b/packages/scripts/src/applyPatches.ts index 5128b3e2d..3d7ab0c44 100644 --- a/packages/scripts/src/applyPatches.ts +++ b/packages/scripts/src/applyPatches.ts @@ -79,6 +79,7 @@ while (true) { const patchedStrings = { ...oldStrings, ...newStrings }; const patchedContent = stringifyYaml(patchedStrings); + await mkdir(`${PATCHES_ROOT}/Data/Strings`, { recursive: true }); await writeFile( `${PATCHES_ROOT}/Data/Strings/en.yaml`, new Uint8Array(writeDVPL(Buffer.from(patchedContent))), From 56933ddfacc95f45d8f4b08532cda2b19000b07b Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 22 Jun 2026 20:07:55 -0500 Subject: [PATCH 10/32] debug --- packages/scripts/src/applyPatches.ts | 2 ++ packages/scripts/src/core/vfs/abstract.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/packages/scripts/src/applyPatches.ts b/packages/scripts/src/applyPatches.ts index 3d7ab0c44..9173c71da 100644 --- a/packages/scripts/src/applyPatches.ts +++ b/packages/scripts/src/applyPatches.ts @@ -74,8 +74,10 @@ while (true) { }/en.yaml`, ); const newStrings = parseYaml(await localizationsResponse.text()); + console.log("new scripts computed"); const oldStrings = await vfs.yaml>(`Data/Strings/en.yaml`); + console.log("old strings loaded"); const patchedStrings = { ...oldStrings, ...newStrings }; const patchedContent = stringifyYaml(patchedStrings); diff --git a/packages/scripts/src/core/vfs/abstract.ts b/packages/scripts/src/core/vfs/abstract.ts index 9cae1309b..9ffd25862 100644 --- a/packages/scripts/src/core/vfs/abstract.ts +++ b/packages/scripts/src/core/vfs/abstract.ts @@ -55,6 +55,7 @@ export abstract class AbstractVFS { async yaml(path: string) { const file = await this.text(path); + console.log(file); return parseYaml(file) as Type; } From cdf2aee43fb70fdebfd589e35a2fd85930b5d4bd Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 22 Jun 2026 20:13:52 -0500 Subject: [PATCH 11/32] debug --- packages/scripts/src/core/vfs/abstract.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/scripts/src/core/vfs/abstract.ts b/packages/scripts/src/core/vfs/abstract.ts index 9ffd25862..c1415de7b 100644 --- a/packages/scripts/src/core/vfs/abstract.ts +++ b/packages/scripts/src/core/vfs/abstract.ts @@ -39,6 +39,8 @@ export abstract class AbstractVFS { const raw = await this.raw(resolved); let buffer = raw; + console.log(resolved); + if (resolved.endsWith(".dvpl")) { buffer = new Uint8Array(readDVPL(Buffer.from(raw))); } From fdbbe2f356344008f316d068c992740a26c87a37 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 22 Jun 2026 20:18:25 -0500 Subject: [PATCH 12/32] Update applyPatches.ts --- packages/scripts/src/applyPatches.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/scripts/src/applyPatches.ts b/packages/scripts/src/applyPatches.ts index 9173c71da..c5f22d7a0 100644 --- a/packages/scripts/src/applyPatches.ts +++ b/packages/scripts/src/applyPatches.ts @@ -83,7 +83,7 @@ while (true) { await mkdir(`${PATCHES_ROOT}/Data/Strings`, { recursive: true }); await writeFile( - `${PATCHES_ROOT}/Data/Strings/en.yaml`, + `${PATCHES_ROOT}/Data/Strings/en.yaml.dvpl`, new Uint8Array(writeDVPL(Buffer.from(patchedContent))), ); } From f6dfc4f1760fd233558133a18d36c334c7a627c8 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 22 Jun 2026 20:32:14 -0500 Subject: [PATCH 13/32] what --- packages/scripts/src/applyPatches.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/scripts/src/applyPatches.ts b/packages/scripts/src/applyPatches.ts index c5f22d7a0..f3b6375cd 100644 --- a/packages/scripts/src/applyPatches.ts +++ b/packages/scripts/src/applyPatches.ts @@ -66,18 +66,14 @@ while (true) { } if ("dynamicContentLocalizationsDir" in data) { - console.log("Found dynamic content localizations; patching..."); - const localizationsResponse = await fetch( `${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${ data.dynamicContentLocalizationsDir }/en.yaml`, ); const newStrings = parseYaml(await localizationsResponse.text()); - console.log("new scripts computed"); const oldStrings = await vfs.yaml>(`Data/Strings/en.yaml`); - console.log("old strings loaded"); const patchedStrings = { ...oldStrings, ...newStrings }; const patchedContent = stringifyYaml(patchedStrings); From 3d35fae5cec8a3088dcafab24baaa37b96422090 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Mon, 22 Jun 2026 20:52:51 -0500 Subject: [PATCH 14/32] dont log --- packages/scripts/src/core/vfs/abstract.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/scripts/src/core/vfs/abstract.ts b/packages/scripts/src/core/vfs/abstract.ts index c1415de7b..9cae1309b 100644 --- a/packages/scripts/src/core/vfs/abstract.ts +++ b/packages/scripts/src/core/vfs/abstract.ts @@ -39,8 +39,6 @@ export abstract class AbstractVFS { const raw = await this.raw(resolved); let buffer = raw; - console.log(resolved); - if (resolved.endsWith(".dvpl")) { buffer = new Uint8Array(readDVPL(Buffer.from(raw))); } @@ -57,7 +55,6 @@ export abstract class AbstractVFS { async yaml(path: string) { const file = await this.text(path); - console.log(file); return parseYaml(file) as Type; } From fc27caabdceb66124a0c6da402d472c64366f976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 23 Jun 2026 10:07:54 -0500 Subject: [PATCH 15/32] dvpl --- packages/scripts/src/applyPatches.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/scripts/src/applyPatches.ts b/packages/scripts/src/applyPatches.ts index f3b6375cd..17d0e7453 100644 --- a/packages/scripts/src/applyPatches.ts +++ b/packages/scripts/src/applyPatches.ts @@ -54,12 +54,11 @@ while (true) { console.warn(`Failed to make directory "${dir}"`); } - const isDvpl = path.endsWith(".dvpl"); const buffer = Buffer.from(data); await writeFile( - `${PATCHES_ROOT}/Data/${path}${isDvpl ? "" : ".dvpl"}`, - new Uint8Array(isDvpl ? buffer : writeDVPL(buffer)), + `${PATCHES_ROOT}/Data/${path}`, + new Uint8Array(buffer), ); bar.tick(); @@ -79,8 +78,8 @@ while (true) { await mkdir(`${PATCHES_ROOT}/Data/Strings`, { recursive: true }); await writeFile( - `${PATCHES_ROOT}/Data/Strings/en.yaml.dvpl`, - new Uint8Array(writeDVPL(Buffer.from(patchedContent))), + `${PATCHES_ROOT}/Data/Strings/en.yaml`, + new Uint8Array((Buffer.from(patchedContent))), ); } From 3e421c7eb703e3f8ae80c5620f10a15a74e4f96a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 23 Jun 2026 10:11:18 -0500 Subject: [PATCH 16/32] done --- packages/scripts/src/applyPatches.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/scripts/src/applyPatches.ts b/packages/scripts/src/applyPatches.ts index 17d0e7453..a43ca66be 100644 --- a/packages/scripts/src/applyPatches.ts +++ b/packages/scripts/src/applyPatches.ts @@ -64,6 +64,8 @@ while (true) { bar.tick(); } + console.log('patches done for patch') + if ("dynamicContentLocalizationsDir" in data) { const localizationsResponse = await fetch( `${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${ From 03b8b89a17287ac8d40fbaad05c1ae4c5096069e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 23 Jun 2026 10:14:37 -0500 Subject: [PATCH 17/32] log --- packages/scripts/src/applyPatches.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/scripts/src/applyPatches.ts b/packages/scripts/src/applyPatches.ts index a43ca66be..66290f3c8 100644 --- a/packages/scripts/src/applyPatches.ts +++ b/packages/scripts/src/applyPatches.ts @@ -67,6 +67,11 @@ while (true) { console.log('patches done for patch') if ("dynamicContentLocalizationsDir" in data) { + console.log( + `${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${ + data.dynamicContentLocalizationsDir + }/en.yaml`, + ); const localizationsResponse = await fetch( `${assertSecret(import.meta.env.WOTB_DLC_CDN)}/dlc/${ data.dynamicContentLocalizationsDir From 55deb30607539e32abf6c41a8ce7aeaeb9771207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 23 Jun 2026 10:20:22 -0500 Subject: [PATCH 18/32] logs --- packages/scripts/src/applyPatches.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/scripts/src/applyPatches.ts b/packages/scripts/src/applyPatches.ts index 66290f3c8..9d6ed046c 100644 --- a/packages/scripts/src/applyPatches.ts +++ b/packages/scripts/src/applyPatches.ts @@ -77,17 +77,23 @@ while (true) { data.dynamicContentLocalizationsDir }/en.yaml`, ); + console.log('fetched') const newStrings = parseYaml(await localizationsResponse.text()); + console.log('got new strings') const oldStrings = await vfs.yaml>(`Data/Strings/en.yaml`); + console.log('got old strings') const patchedStrings = { ...oldStrings, ...newStrings }; const patchedContent = stringifyYaml(patchedStrings); + console.log('stringified') await mkdir(`${PATCHES_ROOT}/Data/Strings`, { recursive: true }); + console.log('mkdir') await writeFile( `${PATCHES_ROOT}/Data/Strings/en.yaml`, new Uint8Array((Buffer.from(patchedContent))), ); + console.log('file') } patchIndex++; From a8e8d20cf1d47494b3c139d0997e790c99eeb5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 23 Jun 2026 10:26:05 -0500 Subject: [PATCH 19/32] break --- packages/scripts/src/applyPatches.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/scripts/src/applyPatches.ts b/packages/scripts/src/applyPatches.ts index 9d6ed046c..7f39d68c3 100644 --- a/packages/scripts/src/applyPatches.ts +++ b/packages/scripts/src/applyPatches.ts @@ -24,7 +24,10 @@ while (true) { )}/dlc/s${currentVersion}_${patchIndex}.yaml`, ); - if (response.status === 200) { + console.log(patchIndex, response.status) + + if (!response.ok) break; + console.log(`Applying patch ${patchIndex}...`); const data = parseYaml(await response.text()); @@ -97,5 +100,4 @@ while (true) { } patchIndex++; - } else break; } From 1cc8b26b16a4bd166e897015175b3de012df71c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 23 Jun 2026 10:30:56 -0500 Subject: [PATCH 20/32] dispose --- packages/scripts/src/applyPatches.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/scripts/src/applyPatches.ts b/packages/scripts/src/applyPatches.ts index 7f39d68c3..edccee966 100644 --- a/packages/scripts/src/applyPatches.ts +++ b/packages/scripts/src/applyPatches.ts @@ -101,3 +101,5 @@ while (true) { patchIndex++; } + +vfs.dispose() From 05572918b13221d2e2b755efd03cb5c7e1c1d41e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Tue, 23 Jun 2026 10:35:27 -0500 Subject: [PATCH 21/32] exit --- packages/scripts/src/applyPatches.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/scripts/src/applyPatches.ts b/packages/scripts/src/applyPatches.ts index edccee966..2c3833188 100644 --- a/packages/scripts/src/applyPatches.ts +++ b/packages/scripts/src/applyPatches.ts @@ -103,3 +103,4 @@ while (true) { } vfs.dispose() +process.exit(0); From b2eb74914ff6954a20e420f011328c1d391f05f6 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Fri, 26 Jun 2026 13:22:24 -0500 Subject: [PATCH 22/32] optimize lighting loop --- .../TankSandbox/components/Lighting.tsx | 160 ++++++++++-------- 1 file changed, 94 insertions(+), 66 deletions(-) diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx index a5d6fa550..b5acd9e9c 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx @@ -1,9 +1,9 @@ -import { useFrame, useThree } from "@react-three/fiber"; -import { times } from "lodash-es"; +import { useFrame } from "@react-three/fiber"; +import { clamp, times } from "lodash-es"; import { Quicklime } from "quicklime"; -import { useEffect, useRef } from "react"; +import { useEffect, useRef, useState, type RefObject } from "react"; import { HemisphereLight, SpotLight, type Group } from "three"; -import { clamp, degToRad, lerp } from "three/src/math/MathUtils.js"; +import { degToRad, lerp } from "three/src/math/MathUtils.js"; import { Tankopedia } from "../../../../../../stores/tankopedia"; import { TankopediaPersistent } from "../../../../../../stores/tankopediaPersistent"; import { HelpingSpotLight } from "../../../../../HelpingSpotLight"; @@ -25,39 +25,105 @@ export const transitionEvent = new Quicklime(0); export function Lighting() { const wrapper = useRef(null!); - const t0 = useRef(0); - const transition = useRef(false); - const clock = useThree((state) => state.clock); - const display = Tankopedia.use((state) => state.display); - const requestedDisplay = Tankopedia.use((state) => state.requestedDisplay); - const animationTime = useRef(REVEAL_ANIMATION_TIME); + const highGraphics = TankopediaPersistent.use((state) => state.highGraphics); + const requestedDisplay = Tankopedia.use((state) => state.requestedDisplay); + + const animationTime = useRef(REVEAL_ANIMATION_TIME); + const t0 = useRef(performance.now() / 1e3 - animationTime.current); + + const isRevealing = useRef(true); + + const [animate, setAnimate] = useState(true); + + console.log(animate); useEffect(() => { Tankopedia.mutate((draft) => { draft.revealed = true; }); - - t0.current = performance.now() / 1000 - REVEAL_ANIMATION_TIME; }, []); + useEffect(() => { + if (isRevealing.current) { + isRevealing.current = false; + } else { + animationTime.current = TRANSITION_ANIMATION_TIME; + t0.current = performance.now() / 1e3; + } + + setAnimate(true); + }, [requestedDisplay]); + + return ( + <> + {animate && ( + { + setAnimate(false); + }} + /> + )} + + + + + {times(LIGHTS_COUNT, (index) => { + const x = index / (LIGHTS_COUNT - 1); + const theta = 2 * Math.PI * (index / LIGHTS_COUNT) + THETA_OFFSET; + const position = [ + LIGHT_DISTANCE * Math.sin(theta), + lerp(LIGHT_HEIGHT_0, LIGHT_HEIGHT_1, x), + LIGHT_DISTANCE * Math.cos(theta), + ] as const; + const intensity = lerp(INTENSITY_0, INTENSITY_1, x); + + return ( + + ); + })} + + + ); +} + +interface AnimatorProps { + stop: () => void; + + t0: RefObject; + animationTime: RefObject; + wrapper: RefObject; +} + +function Animator({ stop, t0, animationTime, wrapper }: AnimatorProps) { + const requestedDisplay = Tankopedia.use((state) => state.requestedDisplay); + useFrame(({ invalidate }) => { - if (transition.current) { - transition.current = false; - t0.current = performance.now() / 1000; + const dt = performance.now() / 1e3 - t0.current; + const x = clamp(dt / animationTime.current, 0, 2); + + console.log(x); + + if (x === 2) { + stop(); + return; } - const x = clamp( - (performance.now() / 1000 - t0.current) / animationTime.current, - 0, - 2, - ); const t = (0.5 * Math.sin(Math.PI * (x + 0.5)) + 0.5) ** 2; - if (t !== transitionEvent.last) { - transitionEvent.dispatch(t); - } - for (const child of wrapper.current.children) { if (child instanceof SpotLight) { child.angle = ANGLE * t; @@ -66,53 +132,15 @@ export function Lighting() { } } - if (x < 2) invalidate(); + transitionEvent.dispatch(t); + invalidate(); - if ( - x > 1 && - Tankopedia.state.display !== Tankopedia.state.requestedDisplay - ) { + if (x >= 1 && Tankopedia.state.display !== requestedDisplay) { Tankopedia.mutate((draft) => { draft.display = requestedDisplay; }); } }); - useEffect(() => { - if (requestedDisplay === display) return; - - transition.current = true; - animationTime.current = TRANSITION_ANIMATION_TIME; - }, [requestedDisplay]); - - return ( - - - - {times(LIGHTS_COUNT, (index) => { - const x = index / (LIGHTS_COUNT - 1); - const theta = 2 * Math.PI * (index / LIGHTS_COUNT) + THETA_OFFSET; - const position = [ - LIGHT_DISTANCE * Math.sin(theta), - lerp(LIGHT_HEIGHT_0, LIGHT_HEIGHT_1, x), - LIGHT_DISTANCE * Math.cos(theta), - ] as const; - const intensity = lerp(INTENSITY_0, INTENSITY_1, x); - - return ( - - ); - })} - - ); + return null; } From 19f22993f171ab757a78be111f9db1c89ff5c9ea Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Fri, 26 Jun 2026 13:31:40 -0500 Subject: [PATCH 23/32] optimize shot display animator --- .../Armor/components/ShotDisplay.tsx | 120 +++++++++++------- 1 file changed, 73 insertions(+), 47 deletions(-) diff --git a/packages/website/src/components/Armor/components/ShotDisplay.tsx b/packages/website/src/components/Armor/components/ShotDisplay.tsx index b7f8f9d2a..2cf2335db 100644 --- a/packages/website/src/components/Armor/components/ShotDisplay.tsx +++ b/packages/website/src/components/Armor/components/ShotDisplay.tsx @@ -1,9 +1,9 @@ import { J_HAT, K_HAT } from "@blitzkit/core"; import { Box, Flex, Text } from "@radix-ui/themes"; import { Html } from "@react-three/drei"; -import { invalidate, useFrame } from "@react-three/fiber"; +import { useFrame } from "@react-three/fiber"; import { clamp } from "lodash-es"; -import { useEffect, useRef, type ComponentProps } from "react"; +import { useEffect, useRef, type ComponentProps, type RefObject } from "react"; import { BufferGeometry, DoubleSide, @@ -42,11 +42,10 @@ const TRACER_THIN = TRACER_THICK / 2; export function ShotDisplay() { const shot = Tankopedia.use((state) => state.shot); - const inTracer = useRef(null); - const outTracer = useRef(null); - const splashRadiusWrapper = useRef(null); - const splashRadiusMaterial = useRef(null); - let animationStartTime: number | null = null; + const inTracer = useRef(null!); + const outTracer = useRef(null!); + const splashRadiusWrapper = useRef(null!); + const splashRadiusMaterial = useRef(null!); const { locale } = useLocale(); useEffect(() => { @@ -64,10 +63,10 @@ export function ShotDisplay() { outlineMaterial, ).computeLineDistances(); - splashRadiusWrapper.current?.add(outline); + splashRadiusWrapper.current.add(outline); return () => { - splashRadiusWrapper.current?.remove(outline); + splashRadiusWrapper.current.remove(outline); }; } }); @@ -86,44 +85,6 @@ export function ShotDisplay() { } }, [shot]); - useFrame(({ clock }) => { - if (!shot) return; - - const t = clock.elapsedTime; - - if (inTracer.current) { - const tracerT1 = t % 1; - const tracerT2 = (t + 0.5) % 1; - - inTracer.current.scale.set(1, 1 - 2 * Math.abs(tracerT1 - 0.5), 1); - inTracer.current.position.set(0, (1 - tracerT1) * inLength, 0); - - if (outTracer.current) { - outTracer.current.scale.set(1, 1 - 2 * Math.abs(tracerT2 - 0.5), 1); - outTracer.current.position.set(0, tracerT2 * outLength, 0); - } - - invalidate(); - } - - if ( - shot.splashRadius !== undefined && - splashRadiusWrapper.current && - splashRadiusMaterial.current - ) { - if (animationStartTime === null) animationStartTime = t; - - const scale = - clamp(4 * (t - animationStartTime), 0, 1) * shot.splashRadius; - const opacity = 1 - clamp(2 * (t - animationStartTime), 0, 1); - - splashRadiusWrapper.current.scale.set(scale, scale, scale); - splashRadiusMaterial.current.opacity = opacity; - - invalidate(); - } - }); - if (!shot) return null; const inLength = @@ -149,6 +110,15 @@ export function ShotDisplay() { return ( + + {shot.splashRadius && ( ); } + +interface AnimatorProps { + inTracer: RefObject; + outTracer: RefObject; + + splashRadiusWrapper: RefObject; + splashRadiusMaterial: RefObject; + + inLength: number; + outLength: number; +} + +function Animator({ + inTracer, + outTracer, + splashRadiusWrapper, + splashRadiusMaterial, + inLength, + outLength, +}: AnimatorProps) { + const shot = Tankopedia.use((state) => state.shot!); + + let animationStartTime: number | null = null; + + useFrame(({ clock, invalidate }) => { + const t = clock.elapsedTime; + + const tracerT1 = t % 1; + const tracerT2 = (t + 0.5) % 1; + + inTracer.current.scale.set(1, 1 - 2 * Math.abs(tracerT1 - 0.5), 1); + inTracer.current.position.set(0, (1 - tracerT1) * inLength, 0); + + if (outTracer.current) { + outTracer.current.scale.set(1, 1 - 2 * Math.abs(tracerT2 - 0.5), 1); + outTracer.current.position.set(0, tracerT2 * outLength, 0); + } + + invalidate(); + + if (shot.splashRadius !== undefined) { + if (animationStartTime === null) animationStartTime = t; + + const scale = + clamp(4 * (t - animationStartTime), 0, 1) * shot.splashRadius; + const opacity = 1 - clamp(2 * (t - animationStartTime), 0, 1); + + splashRadiusWrapper.current.scale.set(scale, scale, scale); + splashRadiusMaterial.current.opacity = opacity; + + invalidate(); + } + }); + + return null; +} From 63a0143d4f6e11d85949c66fa02f9c1294347df1 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Fri, 26 Jun 2026 13:58:30 -0500 Subject: [PATCH 24/32] optimize scene lighting and rnederer --- .../TankSandbox/components/Lighting.tsx | 16 +++++++--------- .../TankSandbox/components/SceneProps/index.tsx | 12 ++---------- .../HeroSection/components/TankSandbox/index.tsx | 2 +- .../src/stores/tankopediaPersistent/index.ts | 2 +- 4 files changed, 11 insertions(+), 21 deletions(-) diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx index b5acd9e9c..3a172ce5e 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Lighting.tsx @@ -8,17 +8,17 @@ import { Tankopedia } from "../../../../../../stores/tankopedia"; import { TankopediaPersistent } from "../../../../../../stores/tankopediaPersistent"; import { HelpingSpotLight } from "../../../../../HelpingSpotLight"; -const ANGLE = Math.PI * 2 ** -2; +const ANGLE = degToRad(10); const REVEAL_ANIMATION_TIME = 3; const TRANSITION_ANIMATION_TIME = 0.5; -const LIGHTS_COUNT = 5; -const THETA_OFFSET = degToRad(-152); -const LIGHT_DISTANCE = 13; +const LIGHTS_COUNT = 4; +const THETA_OFFSET = degToRad(180 - 45); +const LIGHT_DISTANCE = 20; const LIGHT_HEIGHT_0 = 4; -const LIGHT_HEIGHT_1 = 2; -const INTENSITY_0 = 3.5; -const INTENSITY_1 = 1.5; +const LIGHT_HEIGHT_1 = 6; +const INTENSITY_0 = 6; +const INTENSITY_1 = 3; const HEMISPHERE_INTENSITY = 2; export const transitionEvent = new Quicklime(0); @@ -115,8 +115,6 @@ function Animator({ stop, t0, animationTime, wrapper }: AnimatorProps) { const dt = performance.now() / 1e3 - t0.current; const x = clamp(dt / animationTime.current, 0, 2); - console.log(x); - if (x === 2) { stop(); return; diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/SceneProps/index.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/SceneProps/index.tsx index be871c5ef..b31ce0ee3 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/SceneProps/index.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/SceneProps/index.tsx @@ -1,10 +1,9 @@ -import { invalidate, useFrame } from "@react-three/fiber"; -import { clamp } from "lodash-es"; +import { invalidate } from "@react-three/fiber"; import { Quicklime, type QuicklimeEvent } from "quicklime"; import { useEffect, useRef } from "react"; import { Mesh, MeshStandardMaterial } from "three"; -const SIZE = 2 ** 6; +const SIZE = 14; export const screenshotReadyEvent = new Quicklime(false); @@ -12,11 +11,6 @@ export function SceneProps() { const mesh = useRef(null!); const material = useRef(null); - useFrame(({ camera }) => { - if (!material.current) return; - material.current.opacity = clamp(0.5 * camera.position.y, 0, 0.5); - }); - useEffect(() => { function handleScreenshotReady(event: QuicklimeEvent) { mesh.current.visible = !event.data; @@ -36,11 +30,9 @@ export function SceneProps() { receiveShadow visible={!screenshotReadyEvent.last!} ref={mesh} - renderOrder={-1} > ( localClippingEnabled: true, preserveDrawingBuffer: true, }} - shadows="soft" + shadows="basic" onPointerDown={handlePointerDown} onPointerMissed={() => { Tankopedia.mutate((draft) => { diff --git a/packages/website/src/stores/tankopediaPersistent/index.ts b/packages/website/src/stores/tankopediaPersistent/index.ts index ced9cf380..bf4a618e1 100644 --- a/packages/website/src/stores/tankopediaPersistent/index.ts +++ b/packages/website/src/stores/tankopediaPersistent/index.ts @@ -40,5 +40,5 @@ export const TankopediaPersistent = new Varuna( direction: "ascending", }, }, - "tankopedia-2" + "tankopedia-3", ); From cead140855f16eb66f364d841c5878cb00c92035 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Fri, 26 Jun 2026 14:01:39 -0500 Subject: [PATCH 25/32] optimize intro naimaiton --- .../TankSandbox/components/Control.tsx | 60 +++++++++++-------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Control.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Control.tsx index 191745600..024d6ca45 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Control.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/Control.tsx @@ -19,6 +19,8 @@ const poseDistances: Record = { [Pose.Default]: -1, }; +const inspectModeInitialPosition = new Vector3(-8, 2, -13); + const modelDefinitions = await awaitableModelDefinitions; interface ControlsProps { @@ -77,22 +79,6 @@ export function Controls({ protagonistHullOrigin.y + protagonistTurretOrigin.y + protagonistGunOrigin.y; - const inspectModeInitialPosition = new Vector3(-8, 2, -13); - - const t0 = useRef(Date.now() / 1000); - useFrame(() => { - if (!doAutoRotate) return; - - const now = Date.now() / 1000; - const t = now - t0.current; - - camera.position - .copy(inspectModeInitialPosition) - .applyAxisAngle(I_HAT, (Math.PI / 32) * Math.sin(t / 9)) - .applyAxisAngle(J_HAT, (-Math.PI / 16) * Math.sin(t / 7)); - - invalidate(); - }); useEffect(() => { function handleControlsEnabled(event: QuicklimeEvent) { @@ -249,15 +235,37 @@ export function Controls({ }, []); return ( - + <> + {doAutoRotate && } + + + ); } + +function Animator() { + const clock = useThree((state) => state.clock); + const t0 = useRef(clock.elapsedTime); + + useFrame(({ camera }) => { + const t = clock.elapsedTime - t0.current; + + camera.position + .copy(inspectModeInitialPosition) + .applyAxisAngle(I_HAT, (Math.PI / 32) * Math.sin(t / 9)) + .applyAxisAngle(J_HAT, (-Math.PI / 16) * Math.sin(t / 7)); + + invalidate(); + }); + + return null; +} From 5d2c63fed98550cfd7aee0f6a05519a44676b9c8 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Fri, 26 Jun 2026 14:05:26 -0500 Subject: [PATCH 26/32] clean up some renderer stuff --- packages/website/src/components/Armor/index.tsx | 12 ++++++------ .../components/CameraPositioner.tsx | 2 +- .../components/TankSandbox/components/AutoClear.tsx | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/website/src/components/Armor/index.tsx b/packages/website/src/components/Armor/index.tsx index 580133ab8..69da794dd 100644 --- a/packages/website/src/components/Armor/index.tsx +++ b/packages/website/src/components/Armor/index.tsx @@ -1,9 +1,9 @@ -import { createPortal, useFrame, useThree } from '@react-three/fiber'; -import { memo, useState } from 'react'; -import { DepthTexture, Scene, Vector2 } from 'three'; -import { PrimaryArmorScene } from './components/PrimaryArmorScene'; -import { spacedArmorRenderTarget } from './components/PrimaryArmorSceneComponent/target'; -import { SpacedArmorScene } from './components/SpacedArmorScene'; +import { createPortal, useFrame, useThree } from "@react-three/fiber"; +import { memo, useState } from "react"; +import { DepthTexture, Scene, Vector2 } from "three"; +import { PrimaryArmorScene } from "./components/PrimaryArmorScene"; +import { spacedArmorRenderTarget } from "./components/PrimaryArmorSceneComponent/target"; +import { SpacedArmorScene } from "./components/SpacedArmorScene"; export const Armor = memo(() => { const rootScene = useThree((state) => state.scene); diff --git a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/CameraPositioner.tsx b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/CameraPositioner.tsx index 3243f1d7a..2e2537d4d 100644 --- a/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/CameraPositioner.tsx +++ b/packages/website/src/components/Tankopedia/CharacteristicsSection/components/Characteristics/components/GunFlexibilityVisualizer/components/CameraPositioner.tsx @@ -1,4 +1,4 @@ -import { useFrame } from '@react-three/fiber'; +import { useFrame } from "@react-three/fiber"; export const zoom = 60; diff --git a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/AutoClear.tsx b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/AutoClear.tsx index 7c095b7cd..e792d90bd 100644 --- a/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/AutoClear.tsx +++ b/packages/website/src/components/Tankopedia/HeroSection/components/TankSandbox/components/AutoClear.tsx @@ -1,4 +1,4 @@ -import { useFrame } from '@react-three/fiber'; +import { useFrame } from "@react-three/fiber"; export function AutoClear() { useFrame(({ gl }) => { From c85cd36818b4ab244cf258d177c416dfdc13ab4f Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Sun, 28 Jun 2026 11:11:37 -0500 Subject: [PATCH 27/32] logs --- docs/changelogs/1.30.4.md | 2 +- docs/changelogs/1.30.5.md | 8 ++++++++ package.json | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 docs/changelogs/1.30.5.md diff --git a/docs/changelogs/1.30.4.md b/docs/changelogs/1.30.4.md index 166a121cb..cebe9a7fd 100644 --- a/docs/changelogs/1.30.4.md +++ b/docs/changelogs/1.30.4.md @@ -1,4 +1,4 @@ -# BlitzKit 1.30.3 +# BlitzKit 1.30.4 ## Fixes diff --git a/docs/changelogs/1.30.5.md b/docs/changelogs/1.30.5.md new file mode 100644 index 000000000..f858f4602 --- /dev/null +++ b/docs/changelogs/1.30.5.md @@ -0,0 +1,8 @@ +# BlitzKit 1.30.5 + +## Features + +- Reduced the amount of code that executes for every rendered frame, hopefully improving performance +- Reduced the number of lights by 20% to decrease the amount of shadow calculations +- Decreased the ground size by 80% for an equal reduction in shadow texture sizes +- Added the ability for BlitzKit to dismount the components that handled the intro lighting animation when not animating, reducing checks running every frame diff --git a/package.json b/package.json index 1597733ae..723ec41c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blitzkit", - "version": "1.30.4", + "version": "1.30.5", "license": "BlitzKit License", "private": true, "scripts": { From 41e40de791b3f053cec357056b9a46b3a2445d13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C3=A8sAbhi?= <43380238+tresabhi@users.noreply.github.com> Date: Sat, 4 Jul 2026 22:05:48 -0500 Subject: [PATCH 28/32] New Crowdin updates (#251) * New translations en.json (Ukrainian) [ci skip] * New translations en.json (Ukrainian) [ci skip] * New translations en.json (Ukrainian) [ci skip] --- packages/i18n/strings/uk.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/i18n/strings/uk.json b/packages/i18n/strings/uk.json index 673289de1..02820dbfe 100644 --- a/packages/i18n/strings/uk.json +++ b/packages/i18n/strings/uk.json @@ -919,13 +919,13 @@ "external": "External", "gap": "Gap", "gun": "Gun", - "track": "Tracks" + "track": "Гусениці" }, "status": { - "penetration": "{damage}hp penetration", + "penetration": "{damage} од. шкоди з пробиттям", "blocked": "Заблоковано", "ricochet": "Рикошет", - "splash": "{damage}hp splash" + "splash": "{damage} Од" }, "stats": { "thickness_and_angle": "{thickness}mm {angle}°", @@ -1048,7 +1048,7 @@ "caliber": "Калібр", "penetration": "Бронепробиття", "damage": "Шкода", - "damageWithoutAssault": "Damage without assault shells", + "damageWithoutAssault": "Шкода без урахування золотих снарядів", "clipDamage": "Clipping potential", "moduleDamage": "Шкода по модулях", "explosionRadius": "Радіус розльоту уламків", @@ -1057,7 +1057,7 @@ "dispersion": "Нерухомо", "dispersionMoving": "У русі", "dispersionHullTraversing": "Hull traversing", - "dispersionTurretTraversing": "Turret traversing", + "dispersionTurretTraversing": "Обертання башти", "dispersionShooting": "Shooting", "dispersionGunDamaged": "Gun damaged", "gunDepression": "Depression", @@ -1174,7 +1174,7 @@ }, "performance": { "name": "Performance", - "button": "View tanks", + "button": "Переглянути танки", "description": "Tank performance statistics", "seo_description": "Best tanks and their performances in World of Tanks Blitz", "estimation": { From cdbb7647f09e6d9864b7e669dd3768946e039495 Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Sun, 5 Jul 2026 13:41:21 -0500 Subject: [PATCH 29/32] fixed fill and clip rule naming --- packages/website/src/components/EqualIcon.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/website/src/components/EqualIcon.tsx b/packages/website/src/components/EqualIcon.tsx index 316ec5542..2d52033a0 100644 --- a/packages/website/src/components/EqualIcon.tsx +++ b/packages/website/src/components/EqualIcon.tsx @@ -11,8 +11,8 @@ export function EqualIcon(props: ComponentProps<"svg">) { {...props} > From f2f6d4ff49b6cd3923216c05d75600ba1a1544fa Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Sun, 5 Jul 2026 13:44:04 -0500 Subject: [PATCH 30/32] add persistent count for the number of model users to unload only when uses drops to 0 --- packages/website/src/hooks/useDispose.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/website/src/hooks/useDispose.ts b/packages/website/src/hooks/useDispose.ts index 2ff4e3685..5acc7a6ea 100644 --- a/packages/website/src/hooks/useDispose.ts +++ b/packages/website/src/hooks/useDispose.ts @@ -3,9 +3,19 @@ import { useEffect } from "react"; import { Cache, Group, Mesh, MeshStandardMaterial, Object3D } from "three"; import { GLTFLoader, type GLTF } from "three-stdlib"; +const users: Record = {}; + export function useDispose(gltf: GLTF & ObjectMap, path: string) { useEffect(() => { + if (path in users) { + users[path]++; + } else { + users[path] = 1; + } + return () => { + if (--users[path] > 0) return; + gltf.scene.traverse((object) => { if (object instanceof Mesh) { if (object.material instanceof MeshStandardMaterial) { From b4d5d4c16e97cebaafb8a6c0cf0d6ba17f92182a Mon Sep 17 00:00:00 2001 From: tresabhi <43380238+tresabhi@users.noreply.github.com> Date: Sun, 5 Jul 2026 14:04:09 -0500 Subject: [PATCH 31/32] reduce ground brightness in static mode --- .../components/Armor/components/StaticArmorSceneComponent.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/website/src/components/Armor/components/StaticArmorSceneComponent.tsx b/packages/website/src/components/Armor/components/StaticArmorSceneComponent.tsx index c3e97aca1..aba157b48 100644 --- a/packages/website/src/components/Armor/components/StaticArmorSceneComponent.tsx +++ b/packages/website/src/components/Armor/components/StaticArmorSceneComponent.tsx @@ -264,6 +264,7 @@ export function StaticArmorSceneComponent({ Date: Sun, 5 Jul 2026 14:06:46 -0500 Subject: [PATCH 32/32] logs --- cspell.json | 5 +++++ docs/changelogs/1.30.6.md | 7 +++++++ package.json | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 cspell.json create mode 100644 docs/changelogs/1.30.6.md diff --git a/cspell.json b/cspell.json new file mode 100644 index 000000000..4ec147b19 --- /dev/null +++ b/cspell.json @@ -0,0 +1,5 @@ +{ + "words": [ + "Tankopedia" + ] +} \ No newline at end of file diff --git a/docs/changelogs/1.30.6.md b/docs/changelogs/1.30.6.md new file mode 100644 index 000000000..1e5c9e2a3 --- /dev/null +++ b/docs/changelogs/1.30.6.md @@ -0,0 +1,7 @@ +# BlitzKit 1.30.6 + +## Fixes + +- Tanks no longer "randomly" appear dark in Tankopedia and Mixer +- The ground is now as dark as other modes when Static Armor is selected in Tankopedia +- Fixed some naming issues with the "equal" icon, improving performance a tiny tiny bit diff --git a/package.json b/package.json index 723ec41c6..580b4224b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blitzkit", - "version": "1.30.5", + "version": "1.30.6", "license": "BlitzKit License", "private": true, "scripts": {